<commit_before>package com.intellij.psi.impl.source.resolve;

import com.intellij.psi.*;
import com.intellij.psi.impl.source.Constants;
import com.intellij.psi.impl.source.DummyHolder;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.parsing.Parsing;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.FileElement;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.scope.MethodProcessorSetupFailedException;
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
import com.intellij.psi.scope.processor.MethodResolverProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;

public class PsiResolveHelperImpl implements PsiResolveHelper, Constants {
  private final PsiManager myManager;

  public PsiResolveHelperImpl(PsiManager manager) {
    myManager = manager;
  }

  public ResolveResult resolveConstructor(PsiClassType classType, PsiExpressionList argumentList, PsiElement place) {
    ResolveResult[] result = multiResolveConstructor(classType, argumentList, place);
    if (result.length != 1) return ResolveResult.EMPTY;
    return result[0];
  }

  public ResolveResult[] multiResolveConstructor(PsiClassType type, PsiExpressionList argumentList, PsiElement place) {
    final MethodResolverProcessor processor;
    PsiClassType.ClassResolveResult classResolveResult = type.resolveGenerics();
    final PsiClass aClass = classResolveResult.getElement();
    final ResolveResult[] result;
    if (aClass == null) {
      result = ResolveResult.EMPTY_ARRAY;
    }
    else {
      if (argumentList.getParent() instanceof PsiAnonymousClass) {
        processor = new MethodResolverProcessor((PsiClass)argumentList.getParent(), argumentList, place);
      }
      else {
        processor = new MethodResolverProcessor(aClass, argumentList, place);
      }
      PsiScopesUtil.processScope(aClass, processor, classResolveResult.getSubstitutor(), aClass, place);

      // getting the most suitable myResult
      result = processor.getResult();
    }
    return result;
  }

  public PsiClass resolveReferencedClass(String referenceText, PsiElement context) {
    final FileElement holderElement = new DummyHolder(myManager, context).getTreeElement();
    CompositeElement ref = Parsing.parseJavaCodeReferenceText(myManager, referenceText.toCharArray(), holderElement.getCharTable());
    if (ref == null) return null;
    TreeUtil.addChildren(holderElement, ref);

    return ResolveClassUtil.resolveClass((PsiJavaCodeReferenceElement)SourceTreeToPsiMap.treeElementToPsi(ref));
  }

  public PsiVariable resolveReferencedVariable(String referenceText, PsiElement context) {
    final FileElement holderElement = new DummyHolder(myManager, context).getTreeElement();
    TreeElement ref = Parsing.parseJavaCodeReferenceText(myManager, referenceText.toCharArray(), holderElement.getCharTable());
    if (ref == null) return null;
    TreeUtil.addChildren(holderElement, ref);
    PsiJavaCodeReferenceElement psiRef = (PsiJavaCodeReferenceElement)SourceTreeToPsiMap.treeElementToPsi(ref);
    return ResolveVariableUtil.resolveVariable(psiRef, null, null);
  }

  public boolean isAccessible(PsiMember member, PsiElement place, PsiClass accessObjectClass) {
    return isAccessible(member, member.getModifierList(), place, accessObjectClass);
  }


  public boolean isAccessible(PsiMember member, PsiModifierList modifierList, PsiElement place, PsiClass accessObjectClass) {
    return ResolveUtil.isAccessible(member, member.getContainingClass(), modifierList, place, accessObjectClass);
  }

  public CandidateInfo[] getReferencedMethodCandidates(PsiCallExpression expr, boolean dummyImplicitConstructor) {
    final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(expr);
    try {
      PsiScopesUtil.setupAndRunProcessor(processor, expr, dummyImplicitConstructor);
    }
    catch (MethodProcessorSetupFailedException e) {
      return CandidateInfo.EMPTY_ARRAY;
    }
    return processor.getCandidates();
  }

  public PsiType inferTypeForMethodTypeParameter(final PsiTypeParameter typeParameter,
                                                 final PsiParameter[] parameters,
                                                 PsiExpression[] arguments, PsiSubstitutor partialSubstitutor, PsiElement parent) {
    PsiType substitution = PsiType.NULL;
    if (parameters.length > 0) {
      for (int j = 0; j < arguments.length; j++) {
        PsiExpression argument = arguments[j];
        final PsiParameter parameter = parameters[Math.min(j, parameters.length - 1)];
        if (j >= parameters.length && !parameter.isVarArgs()) break;
        final PsiType currentSubstitution = getSubstitutionForTypeParameter(typeParameter, parameter.getType(),
                                                                                         argument.getType(), true);
        if (currentSubstitution == null) {
          substitution = null;
          break;
        } else if (currentSubstitution instanceof PsiWildcardType) {
          if (substitution instanceof PsiWildcardType) return PsiType.NULL;
        } else if (currentSubstitution == PsiType.NULL) continue;

        if (substitution == PsiType.NULL) {
          substitution = currentSubstitution;
          continue;
        }
        if (!substitution.equals(currentSubstitution) && !substitution.isAssignableFrom(currentSubstitution)) {
          substitution = GenericsUtil.getLeastUpperBound(substitution, currentSubstitution, typeParameter.getManager());
          if (substitution == null) {
            break;
          }
        }
      }
    }

    if (substitution == PsiType.NULL) {
      substitution = inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent);
    }
    return substitution;
  }

  private static PsiType processArgType(PsiType arg, boolean captureWildcard) {
    if (arg instanceof PsiWildcardType) {
      return captureWildcard ? arg : PsiType.NULL;
    } else {
      if (arg == null || arg.getDeepComponentType() instanceof PsiPrimitiveType ||
          PsiUtil.resolveClassInType(arg) != null) return arg;
    }

    return PsiType.NULL;
  }

  private PsiType inferMethodTypeParameterFromParent(final PsiTypeParameter typeParameter,
                                                            PsiSubstitutor substitutor,
                                                            PsiElement parent) {
    PsiTypeParameterListOwner owner = typeParameter.getOwner();
    PsiType substitution = PsiType.NULL;
    if (owner instanceof PsiMethod) {
      if (parent instanceof PsiMethodCallExpression) {
        PsiMethodCallExpression methodCall = (PsiMethodCallExpression)parent;
        substitution = inferMethodTypeParameterFromParent(methodCall.getParent(), methodCall, typeParameter, substitutor);
      }
    }
    return substitution;
  }

  public PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam,
                                                        PsiType param,
                                                        PsiType arg,
                                                        boolean isContraVariantPosition) {
    if (param instanceof PsiEllipsisType) {
      if (arg instanceof PsiArrayType) arg = ((PsiArrayType)arg).getComponentType();
      return getSubstitutionForTypeParameter(typeParam, ((PsiEllipsisType)param).getComponentType(), arg, isContraVariantPosition);
    }

    if (param instanceof PsiArrayType && arg instanceof PsiArrayType) {
      return getSubstitutionForTypeParameter(typeParam, ((PsiArrayType)param).getComponentType(), ((PsiArrayType)arg).getComponentType(),
                                             isContraVariantPosition);
    }

    if (param instanceof PsiClassType) {
      PsiManager manager = typeParam.getManager();
      if (arg instanceof PsiPrimitiveType) {
        arg = ((PsiPrimitiveType)arg).getBoxedType(manager, typeParam.getResolveScope());
        if (arg == null) return PsiType.NULL;
      }

      ResolveResult paramResult = ((PsiClassType)param).resolveGenerics();
      PsiClass paramClass = (PsiClass)paramResult.getElement();
      if (typeParam == paramClass) {
        return arg == null || arg.getDeepComponentType() instanceof PsiPrimitiveType ||
               PsiUtil.resolveClassInType(arg) != null ? arg : PsiType.NULL;
      }
      if (paramClass == null) return PsiType.NULL;

      if (arg instanceof PsiClassType) {<commit_msg>Type inference with arrays and varargs corrected<commit_after>package com.intellij.psi.impl.source.resolve;

import com.intellij.psi.*;
import com.intellij.psi.impl.source.Constants;
import com.intellij.psi.impl.source.DummyHolder;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.parsing.Parsing;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.FileElement;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.scope.MethodProcessorSetupFailedException;
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
import com.intellij.psi.scope.processor.MethodResolverProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;

public class PsiResolveHelperImpl implements PsiResolveHelper, Constants {
  private final PsiManager myManager;

  public PsiResolveHelperImpl(PsiManager manager) {
    myManager = manager;
  }

  public ResolveResult resolveConstructor(PsiClassType classType, PsiExpressionList argumentList, PsiElement place) {
    ResolveResult[] result = multiResolveConstructor(classType, argumentList, place);
    if (result.length != 1) return ResolveResult.EMPTY;
    return result[0];
  }

  public ResolveResult[] multiResolveConstructor(PsiClassType type, PsiExpressionList argumentList, PsiElement place) {
    final MethodResolverProcessor processor;
    PsiClassType.ClassResolveResult classResolveResult = type.resolveGenerics();
    final PsiClass aClass = classResolveResult.getElement();
    final ResolveResult[] result;
    if (aClass == null) {
      result = ResolveResult.EMPTY_ARRAY;
    }
    else {
      if (argumentList.getParent() instanceof PsiAnonymousClass) {
        processor = new MethodResolverProcessor((PsiClass)argumentList.getParent(), argumentList, place);
      }
      else {
        processor = new MethodResolverProcessor(aClass, argumentList, place);
      }
      PsiScopesUtil.processScope(aClass, processor, classResolveResult.getSubstitutor(), aClass, place);

      // getting the most suitable myResult
      result = processor.getResult();
    }
    return result;
  }

  public PsiClass resolveReferencedClass(String referenceText, PsiElement context) {
    final FileElement holderElement = new DummyHolder(myManager, context).getTreeElement();
    CompositeElement ref = Parsing.parseJavaCodeReferenceText(myManager, referenceText.toCharArray(), holderElement.getCharTable());
    if (ref == null) return null;
    TreeUtil.addChildren(holderElement, ref);

    return ResolveClassUtil.resolveClass((PsiJavaCodeReferenceElement)SourceTreeToPsiMap.treeElementToPsi(ref));
  }

  public PsiVariable resolveReferencedVariable(String referenceText, PsiElement context) {
    final FileElement holderElement = new DummyHolder(myManager, context).getTreeElement();
    TreeElement ref = Parsing.parseJavaCodeReferenceText(myManager, referenceText.toCharArray(), holderElement.getCharTable());
    if (ref == null) return null;
    TreeUtil.addChildren(holderElement, ref);
    PsiJavaCodeReferenceElement psiRef = (PsiJavaCodeReferenceElement)SourceTreeToPsiMap.treeElementToPsi(ref);
    return ResolveVariableUtil.resolveVariable(psiRef, null, null);
  }

  public boolean isAccessible(PsiMember member, PsiElement place, PsiClass accessObjectClass) {
    return isAccessible(member, member.getModifierList(), place, accessObjectClass);
  }


  public boolean isAccessible(PsiMember member, PsiModifierList modifierList, PsiElement place, PsiClass accessObjectClass) {
    return ResolveUtil.isAccessible(member, member.getContainingClass(), modifierList, place, accessObjectClass);
  }

  public CandidateInfo[] getReferencedMethodCandidates(PsiCallExpression expr, boolean dummyImplicitConstructor) {
    final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(expr);
    try {
      PsiScopesUtil.setupAndRunProcessor(processor, expr, dummyImplicitConstructor);
    }
    catch (MethodProcessorSetupFailedException e) {
      return CandidateInfo.EMPTY_ARRAY;
    }
    return processor.getCandidates();
  }

  public PsiType inferTypeForMethodTypeParameter(final PsiTypeParameter typeParameter,
                                                 final PsiParameter[] parameters,
                                                 PsiExpression[] arguments, PsiSubstitutor partialSubstitutor, PsiElement parent) {
    PsiType substitution = PsiType.NULL;
    if (parameters.length > 0) {
      for (int j = 0; j < arguments.length; j++) {
        PsiExpression argument = arguments[j];
        final PsiParameter parameter = parameters[Math.min(j, parameters.length - 1)];
        if (j >= parameters.length && !parameter.isVarArgs()) break;
        PsiType parameterType = parameter.getType();
        PsiType argumentType = argument.getType();

        if (parameterType instanceof PsiEllipsisType) {
          parameterType = ((PsiEllipsisType)parameterType).getComponentType();
          if (arguments.length == parameters.length && argumentType instanceof PsiArrayType && !(((PsiArrayType)argumentType).getComponentType() instanceof PsiPrimitiveType)) {
            argumentType = ((PsiArrayType)argumentType).getComponentType();
          }
        }
        final PsiType currentSubstitution = getSubstitutionForTypeParameter(typeParameter, parameterType,
                                                                            argumentType, true);
        if (currentSubstitution == null) {
          substitution = null;
          break;
        } else if (currentSubstitution instanceof PsiWildcardType) {
          if (substitution instanceof PsiWildcardType) return PsiType.NULL;
        } else if (currentSubstitution == PsiType.NULL) continue;

        if (substitution == PsiType.NULL) {
          substitution = currentSubstitution;
          continue;
        }
        if (!substitution.equals(currentSubstitution) && !substitution.isAssignableFrom(currentSubstitution)) {
          substitution = GenericsUtil.getLeastUpperBound(substitution, currentSubstitution, typeParameter.getManager());
          if (substitution == null) {
            break;
          }
        }
      }
    }

    if (substitution == PsiType.NULL) {
      substitution = inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent);
    }
    return substitution;
  }

  private static PsiType processArgType(PsiType arg, boolean captureWildcard) {
    if (arg instanceof PsiWildcardType) {
      return captureWildcard ? arg : PsiType.NULL;
    } else {
      if (arg == null || arg.getDeepComponentType() instanceof PsiPrimitiveType ||
          PsiUtil.resolveClassInType(arg) != null) return arg;
    }

    return PsiType.NULL;
  }

  private PsiType inferMethodTypeParameterFromParent(final PsiTypeParameter typeParameter,
                                                            PsiSubstitutor substitutor,
                                                            PsiElement parent) {
    PsiTypeParameterListOwner owner = typeParameter.getOwner();
    PsiType substitution = PsiType.NULL;
    if (owner instanceof PsiMethod) {
      if (parent instanceof PsiMethodCallExpression) {
        PsiMethodCallExpression methodCall = (PsiMethodCallExpression)parent;
        substitution = inferMethodTypeParameterFromParent(methodCall.getParent(), methodCall, typeParameter, substitutor);
      }
    }
    return substitution;
  }

  public PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam,
                                                        PsiType param,
                                                        PsiType arg,
                                                        boolean isContraVariantPosition) {
    //Ellipsis types are analyzed somewhere else
    LOG.assertTrue(!(param instanceof PsiEllipsisType));

    if (param instanceof PsiArrayType && arg instanceof PsiArrayType) {
      return getSubstitutionForTypeParameter(typeParam, ((PsiArrayType)param).getComponentType(), ((PsiArrayType)arg).getComponentType(),
                                             isContraVariantPosition);
    }

    if (param instanceof PsiClassType) {
      PsiManager manager = typeParam.getManager();
      if (arg instanceof PsiPrimitiveType) {
        arg = ((PsiPrimitiveType)arg).getBoxedType(manager, typeParam.getResolveScope());
        if (arg == null) return PsiType.NULL;
      }

      ResolveResult paramResult = ((PsiClassType)param).resolveGenerics();
      PsiClass paramClass = (PsiClass)paramResult.getElement();
      if (typeParam == paramClass) {
        return arg == null || arg.getDeepComponentType() instanceof PsiPrimitiveType ||
               PsiUtil.resolveClassInType(arg) != null ? arg : PsiType.NULL;
      }
      if (paramClass == null) return PsiType.NULL;

      if (arg instanceof PsiClassType) {
{'fraction_non_alphanumeric': 0.08419109420452002, 'fraction_numerical': 0.0005594092638174089, 'mean_word_length': 3.364501953125, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 39, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6203607', 'n_tokens_mistral': 4720, 'n_tokens_neox': 4588, 'n_words': 975}