<commit_before>/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.codeInsight.daemon.impl.quickfix;

import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.JavaProjectCodeInsightSettings;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.HintAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.*;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Processor;
import com.intellij.util.containers.LinkedMultiMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;

import java.util.*;

public class StaticImportMethodFix implements IntentionAction, HintAction {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix");
  private final SmartPsiElementPointer<PsiMethodCallExpression> myMethodCall;
  private List<PsiMethod> candidates;

  public StaticImportMethodFix(@NotNull PsiMethodCallExpression methodCallExpression) {
    myMethodCall = SmartPointerManager.getInstance(methodCallExpression.getProject()).createSmartPsiElementPointer(methodCallExpression);
  }

  @Override
  @NotNull
  public String getText() {
    String text = QuickFixBundle.message("static.import.method.text");
    if (candidates != null && candidates.size() == 1) {
      text += " '" + getMethodPresentableText() + "'";
    }
    else {
      text += "...";
    }
    return text;
  }

  @NotNull
  private String getMethodPresentableText() {
    return PsiFormatUtil.formatMethod(candidates.get(0), PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME |
                                                                               PsiFormatUtilBase.SHOW_CONTAINING_CLASS |
                                                                               PsiFormatUtilBase.SHOW_FQ_NAME, 0);
  }

  @Override
  @NotNull
  public String getFamilyName() {
    return getText();
  }

  @Override
  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    return PsiUtil.isLanguageLevel5OrHigher(file)
           && file instanceof PsiJavaFile
           && myMethodCall.getElement() != null
           && myMethodCall.getElement().isValid()
           && myMethodCall.getElement().getMethodExpression().getQualifierExpression() == null
           && myMethodCall.getElement().resolveMethod() == null
           && file.getManager().isInProject(file)
           && !(candidates == null ? candidates = getMethodsToImport() : candidates).isEmpty()
      ;
  }

  private PsiType getExpectedType() {
    final PsiMethodCallExpression methodCall = myMethodCall.getElement();
    if (methodCall == null) return null;
    final PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent());

    if (parent instanceof PsiVariable) {
      if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(((PsiVariable)parent).getInitializer()))) {
        return ((PsiVariable)parent).getType();
      }
    }
    else if (parent instanceof PsiAssignmentExpression) {
      if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)parent).getRExpression()))) {
        return ((PsiAssignmentExpression)parent).getLExpression().getType();
      }
    }
    else if (parent instanceof PsiReturnStatement) {
      final PsiElement psiElement = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, PsiMethod.class);
      if (psiElement instanceof PsiLambdaExpression) {
        return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)psiElement).getFunctionalInterfaceType());
      }
      else if (psiElement instanceof PsiMethod) {
        return ((PsiMethod)psiElement).getReturnType();
      }
    }
    else if (parent instanceof PsiExpressionList) {
      final PsiElement pParent = parent.getParent();
      if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) {
        final JavaResolveResult resolveResult = ((PsiCallExpression)pParent).resolveMethodGenerics();
        final PsiElement psiElement = resolveResult.getElement();
        if (psiElement instanceof PsiMethod) {
          final PsiMethod psiMethod = (PsiMethod)psiElement;
          final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
          final int idx = ArrayUtilRt.find(((PsiExpressionList)parent).getExpressions(), PsiUtil.skipParenthesizedExprUp(methodCall));
          if (idx > -1 && parameters.length > 0) {
            PsiType parameterType = parameters[Math.min(idx, parameters.length - 1)].getType();
            if (idx >= parameters.length - 1) {
              final PsiParameter lastParameter = parameters[parameters.length - 1];
              if (lastParameter.isVarArgs()) {
                parameterType = ((PsiEllipsisType)lastParameter.getType()).getComponentType();
              }
            }
            return resolveResult.getSubstitutor().substitute(parameterType);
          }
          else {
            return null;
          }
        }
      }
    }
    else if (parent instanceof PsiLambdaExpression) {
      return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
    }
    return null;
  }

  @NotNull
  private List<PsiMethod> getMethodsToImport() {
    final Project project = myMethodCall.getProject();
    PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
    final PsiMethodCallExpression element = myMethodCall.getElement();
    PsiReferenceExpression reference = element.getMethodExpression();
    final PsiExpressionList argumentList = element.getArgumentList();
    String name = reference.getReferenceName();
    final List<PsiMethod> list = new ArrayList<PsiMethod>();
    if (name == null) return list;
    GlobalSearchScope scope = element.getResolveScope();
    final Map<PsiClass, Boolean> possibleClasses = new HashMap<PsiClass, Boolean>();
    final PsiType expectedType = getExpectedType();
    final List<PsiMethod> applicableList = new ArrayList<PsiMethod>();
    final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper();

    final MultiMap<PsiClass, PsiMethod> deprecated = new LinkedMultiMap<PsiClass, PsiMethod>();
    final MultiMap<PsiClass, PsiMethod> suggestions = new LinkedMultiMap<PsiClass, PsiMethod>();
    class RegisterMethodsProcessor {
      private void registerMethod(PsiClass containingClass, Collection<PsiMethod> methods) {
        final Boolean alreadyMentioned = possibleClasses.get(containingClass);
        if (alreadyMentioned == Boolean.TRUE) return;
        if (alreadyMentioned == null) {
          list.addAll(methods);
          possibleClasses.put(containingClass, false);
        }
        for (PsiMethod method : methods) {
          if (!PsiUtil.isAccessible(project, method, element, containingClass)) {
            continue;
          }
          PsiSubstitutor substitutorForMethod = resolveHelper
            .inferTypeArguments(method.getTypeParameters(), method.getParameterList().getParameters(),
                                argumentList.getExpressions(),
                                PsiSubstitutor.EMPTY, element.getParent(), DefaultParameterTypeInferencePolicy.INSTANCE);
          if (PsiUtil.isApplicable(method, substitutorForMethod, argumentList)) {
            final PsiType returnType = substitutorForMethod.substitute(method.getReturnType());
            if (expectedType == null || returnType == null || TypeConversionUtil.isAssignable(expectedType, returnType)) {
              applicableList.add(method);
              possibleClasses.put(containingClass, true);
              break;
            }<commit_msg>static imports: preserve one named method per class even if no applicable method found<commit_after>/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.codeInsight.daemon.impl.quickfix;

import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.JavaProjectCodeInsightSettings;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.HintAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.*;
import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Processor;
import com.intellij.util.containers.LinkedMultiMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;

import java.util.*;

public class StaticImportMethodFix implements IntentionAction, HintAction {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix");
  private final SmartPsiElementPointer<PsiMethodCallExpression> myMethodCall;
  private List<PsiMethod> candidates;

  public StaticImportMethodFix(@NotNull PsiMethodCallExpression methodCallExpression) {
    myMethodCall = SmartPointerManager.getInstance(methodCallExpression.getProject()).createSmartPsiElementPointer(methodCallExpression);
  }

  @Override
  @NotNull
  public String getText() {
    String text = QuickFixBundle.message("static.import.method.text");
    if (candidates != null && candidates.size() == 1) {
      text += " '" + getMethodPresentableText() + "'";
    }
    else {
      text += "...";
    }
    return text;
  }

  @NotNull
  private String getMethodPresentableText() {
    return PsiFormatUtil.formatMethod(candidates.get(0), PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME |
                                                                               PsiFormatUtilBase.SHOW_CONTAINING_CLASS |
                                                                               PsiFormatUtilBase.SHOW_FQ_NAME, 0);
  }

  @Override
  @NotNull
  public String getFamilyName() {
    return getText();
  }

  @Override
  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    return PsiUtil.isLanguageLevel5OrHigher(file)
           && file instanceof PsiJavaFile
           && myMethodCall.getElement() != null
           && myMethodCall.getElement().isValid()
           && myMethodCall.getElement().getMethodExpression().getQualifierExpression() == null
           && myMethodCall.getElement().resolveMethod() == null
           && file.getManager().isInProject(file)
           && !(candidates == null ? candidates = getMethodsToImport() : candidates).isEmpty()
      ;
  }

  private PsiType getExpectedType() {
    final PsiMethodCallExpression methodCall = myMethodCall.getElement();
    if (methodCall == null) return null;
    final PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent());

    if (parent instanceof PsiVariable) {
      if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(((PsiVariable)parent).getInitializer()))) {
        return ((PsiVariable)parent).getType();
      }
    }
    else if (parent instanceof PsiAssignmentExpression) {
      if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)parent).getRExpression()))) {
        return ((PsiAssignmentExpression)parent).getLExpression().getType();
      }
    }
    else if (parent instanceof PsiReturnStatement) {
      final PsiElement psiElement = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, PsiMethod.class);
      if (psiElement instanceof PsiLambdaExpression) {
        return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)psiElement).getFunctionalInterfaceType());
      }
      else if (psiElement instanceof PsiMethod) {
        return ((PsiMethod)psiElement).getReturnType();
      }
    }
    else if (parent instanceof PsiExpressionList) {
      final PsiElement pParent = parent.getParent();
      if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) {
        final JavaResolveResult resolveResult = ((PsiCallExpression)pParent).resolveMethodGenerics();
        final PsiElement psiElement = resolveResult.getElement();
        if (psiElement instanceof PsiMethod) {
          final PsiMethod psiMethod = (PsiMethod)psiElement;
          final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
          final int idx = ArrayUtilRt.find(((PsiExpressionList)parent).getExpressions(), PsiUtil.skipParenthesizedExprUp(methodCall));
          if (idx > -1 && parameters.length > 0) {
            PsiType parameterType = parameters[Math.min(idx, parameters.length - 1)].getType();
            if (idx >= parameters.length - 1) {
              final PsiParameter lastParameter = parameters[parameters.length - 1];
              if (lastParameter.isVarArgs()) {
                parameterType = ((PsiEllipsisType)lastParameter.getType()).getComponentType();
              }
            }
            return resolveResult.getSubstitutor().substitute(parameterType);
          }
          else {
            return null;
          }
        }
      }
    }
    else if (parent instanceof PsiLambdaExpression) {
      return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
    }
    return null;
  }

  @NotNull
  private List<PsiMethod> getMethodsToImport() {
    final Project project = myMethodCall.getProject();
    PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
    final PsiMethodCallExpression element = myMethodCall.getElement();
    PsiReferenceExpression reference = element.getMethodExpression();
    final PsiExpressionList argumentList = element.getArgumentList();
    String name = reference.getReferenceName();
    final List<PsiMethod> list = new ArrayList<PsiMethod>();
    if (name == null) return list;
    GlobalSearchScope scope = element.getResolveScope();
    final Map<PsiClass, Boolean> possibleClasses = new HashMap<PsiClass, Boolean>();
    final PsiType expectedType = getExpectedType();
    final List<PsiMethod> applicableList = new ArrayList<PsiMethod>();
    final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper();

    final MultiMap<PsiClass, PsiMethod> deprecated = new LinkedMultiMap<PsiClass, PsiMethod>();
    final MultiMap<PsiClass, PsiMethod> suggestions = new LinkedMultiMap<PsiClass, PsiMethod>();
    class RegisterMethodsProcessor {
      private void registerMethod(PsiClass containingClass, Collection<PsiMethod> methods) {
        final Boolean alreadyMentioned = possibleClasses.get(containingClass);
        if (alreadyMentioned == Boolean.TRUE) return;
        if (alreadyMentioned == null) {
          if (!methods.isEmpty()) {
            list.add(methods.iterator().next());
          }
          possibleClasses.put(containingClass, false);
        }
        for (PsiMethod method : methods) {
          if (!PsiUtil.isAccessible(project, method, element, containingClass)) {
            continue;
          }
          PsiSubstitutor substitutorForMethod = resolveHelper
            .inferTypeArguments(method.getTypeParameters(), method.getParameterList().getParameters(),
                                argumentList.getExpressions(),
                                PsiSubstitutor.EMPTY, element.getParent(), DefaultParameterTypeInferencePolicy.INSTANCE);
          if (PsiUtil.isApplicable(method, substitutorForMethod, argumentList)) {
            final PsiType returnType = substitutorForMethod.substitute(method.getReturnType());
            if (expectedType == null || returnType == null || TypeConversionUtil.isAssignable(expectedType, returnType)) {
              applicableList.add(method);
              possibleClasses.put(containingClass, true);
              break;
            }
{'fraction_non_alphanumeric': 0.09656256777271742, 'fraction_numerical': 0.002277163305139883, 'mean_word_length': 3.644925711407706, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '987687', 'n_tokens_mistral': 4882, 'n_tokens_neox': 4796, 'n_words': 1003}