private static boolean acceptExtendsBound(PsiClassType extendsBound, int depth) { PsiType[] parameters = extendsBound.getParameters(); if (parameters.length == 1) { PsiType argType = parameters[0]; if (argType instanceof PsiCapturedWildcardType && depth == 0) { argType = ((PsiCapturedWildcardType) argType).getWildcard(); } if (argType instanceof PsiWildcardType) { if (!((PsiWildcardType) argType).isBounded()) return true; final PsiType bound = ((PsiWildcardType) argType).getExtendsBound(); if (bound instanceof PsiClassType && TypeConversionUtil.erasure(bound).equals(TypeConversionUtil.erasure(extendsBound))) { return acceptExtendsBound((PsiClassType) bound, depth + 1); } if (bound instanceof PsiIntersectionType) { for (PsiType extendsType : ((PsiIntersectionType) bound).getConjuncts()) { if (acceptExtendsBound(extendsBound, extendsType)) { return true; } } } } } return false; }
@NotNull @Override public MyResult weigh(@NotNull LookupElement item) { final Object object = item.getObject(); if (object instanceof PsiClass) { if (object instanceof PsiTypeParameter) return MyResult.typeParameter; if (myTypeParameter != null && object.equals( PsiUtil.resolveClassInType( TypeConversionUtil.typeParameterErasure(myTypeParameter)))) { return MyResult.exactlyExpected; } } if (myExpectedTypes == null) return MyResult.normal; PsiType itemType = JavaCompletionUtil.getLookupElementType(item); if (itemType == null || !itemType.isValid()) return MyResult.normal; if (object instanceof PsiClass) { for (final ExpectedTypeInfo info : myExpectedTypes) { if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()) .equals(TypeConversionUtil.erasure(itemType))) { return AbstractExpectedTypeSkipper.skips(item, myLocation) ? MyResult.expectedNoSelect : MyResult.exactlyExpected; } } } for (final ExpectedTypeInfo expectedInfo : myExpectedTypes) { final PsiType defaultType = expectedInfo.getDefaultType(); final PsiType expectedType = expectedInfo.getType(); if (!expectedType.isValid()) { return MyResult.normal; } if (defaultType != expectedType) { if (defaultType.equals(itemType)) { return MyResult.exactlyDefault; } if (defaultType.isAssignableFrom(itemType)) { return MyResult.ofDefaultType; } } if (PsiType.VOID.equals(itemType) && PsiType.VOID.equals(expectedType)) { return MyResult.exactlyExpected; } } return MyResult.normal; }
public static PsiType captureReturnType( PsiMethodCallExpression call, PsiMethod method, PsiType ret, JavaResolveResult result, LanguageLevel languageLevel) { PsiSubstitutor substitutor = result.getSubstitutor(); PsiType substitutedReturnType = substitutor.substitute(ret); if (substitutedReturnType == null) { return TypeConversionUtil.erasure(ret); } if (InferenceSession.wasUncheckedConversionPerformed(call)) { // 18.5.2 // if unchecked conversion was necessary, then this substitution provides the parameter types // of the invocation type, // while the return type and thrown types are given by the erasure of m's type (without // applying θ'). // due to https://bugs.openjdk.java.net/browse/JDK-8135087 erasure is called on // substitutedReturnType and not on ret type itself as by spec return TypeConversionUtil.erasure(substitutedReturnType); } // 15.12.2.6. Method Invocation Type // If unchecked conversion was necessary for the method to be applicable, // the parameter types of the invocation type are the parameter types of the method's type, // and the return type and thrown types are given by the erasures of the return type and thrown // types of the method's type. if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && (method.hasTypeParameters() || JavaVersionService.getInstance().isAtLeast(call, JavaSdkVersion.JDK_1_8)) && result instanceof MethodCandidateInfo && ((MethodCandidateInfo) result).isApplicable()) { final PsiType[] args = call.getArgumentList().getExpressionTypes(); final boolean allowUncheckedConversion = false; final int applicabilityLevel = PsiUtil.getApplicabilityLevel( method, substitutor, args, languageLevel, allowUncheckedConversion, true); if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) { return TypeConversionUtil.erasure(substitutedReturnType); } } if (PsiUtil.isRawSubstitutor(method, substitutor)) { final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret); if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) { return returnTypeErasure; } } return PsiUtil.captureToplevelWildcards(substitutedReturnType, call); }
private boolean hardEquals( PsiModifierListOwner psiVar, PsiType varType, boolean negated, DfaVariableValue qualifier) { return psiVar == myVariable && Comparing.equal( TypeConversionUtil.erasure(varType), TypeConversionUtil.erasure(myVarType)) && negated == myIsNegated && (myQualifier == null ? qualifier == null : myQualifier.hardEquals( qualifier.getPsiVariable(), qualifier.getVariableType(), qualifier.isNegated(), qualifier.getQualifier())); }
public static boolean acceptExtendsBound(PsiType extendsType, PsiType extendsBound) { if (Comparing.equal( TypeConversionUtil.erasure(extendsType), TypeConversionUtil.erasure(extendsBound))) { if (extendsBound instanceof PsiClassType) { if (acceptExtendsBound((PsiClassType) extendsBound, 0)) return true; } else if (extendsBound instanceof PsiIntersectionType) { for (PsiType psiType : ((PsiIntersectionType) extendsBound).getConjuncts()) { if (psiType instanceof PsiClassType) { if (acceptExtendsBound((PsiClassType) psiType, 0)) return true; } } } } return false; }
protected PsiType processLocalVariableInitializer(PsiExpression initializer) { PsiType result = null; if (null != initializer && !(initializer instanceof PsiArrayInitializerExpression)) { if (!recursionBreaker.get().contains(initializer)) { recursionBreaker.get().add(initializer); try { result = initializer.getType(); } finally { recursionBreaker.get().remove(initializer); } if (initializer instanceof PsiNewExpression) { final PsiJavaCodeReferenceElement reference = ((PsiNewExpression) initializer).getClassOrAnonymousClassReference(); if (reference != null) { final PsiReferenceParameterList parameterList = reference.getParameterList(); if (parameterList != null) { final PsiTypeElement[] elements = parameterList.getTypeParameterElements(); if (elements.length == 1 && elements[0].getType() instanceof PsiDiamondType) { result = TypeConversionUtil.erasure(result); } } } } } } return result; }
public static void replaceMovedMemberTypeParameters( final PsiElement member, final Iterable<PsiTypeParameter> parametersIterable, final PsiSubstitutor substitutor, final GroovyPsiElementFactory factory) { final Map<PsiElement, PsiElement> replacement = new LinkedHashMap<PsiElement, PsiElement>(); for (PsiTypeParameter parameter : parametersIterable) { PsiType substitutedType = substitutor.substitute(parameter); if (substitutedType == null) { substitutedType = TypeConversionUtil.erasure(factory.createType(parameter)); } PsiElement scopeElement = member instanceof GrField ? member.getParent() : member; for (PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(scopeElement))) { final PsiElement element = reference.getElement(); final PsiElement parent = element.getParent(); if (parent instanceof PsiTypeElement) { replacement.put(parent, factory.createTypeElement(substitutedType)); } else if (element instanceof GrCodeReferenceElement && substitutedType instanceof PsiClassType) { replacement.put( element, factory.createReferenceElementByType((PsiClassType) substitutedType)); } } } for (PsiElement element : replacement.keySet()) { if (element.isValid()) { element.replace(replacement.get(element)); } } }
@Nullable private static PsiType getTypeFromMapAccess(@NotNull GrReferenceExpressionImpl ref) { // map access GrExpression qualifier = ref.getQualifierExpression(); if (qualifier != null) { PsiType qType = qualifier.getNominalType(); if (qType instanceof PsiClassType) { PsiClassType.ClassResolveResult qResult = ((PsiClassType) qType).resolveGenerics(); PsiClass clazz = qResult.getElement(); if (clazz != null) { PsiClass mapClass = JavaPsiFacade.getInstance(ref.getProject()) .findClass(CommonClassNames.JAVA_UTIL_MAP, ref.getResolveScope()); if (mapClass != null && mapClass.getTypeParameters().length == 2) { PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor()); if (substitutor != null) { return TypeConversionUtil.erasure( substitutor.substitute(mapClass.getTypeParameters()[1])); } } } } } return null; }
@Nullable private static PsiType getInferredTypes( GrReferenceExpressionImpl refExpr, @Nullable PsiElement resolved) { final GrExpression qualifier = refExpr.getQualifier(); if (qualifier == null && !(resolved instanceof PsiClass)) { return TypeInferenceHelper.getCurrentContext().getVariableType(refExpr); } else if (qualifier != null) { // map access PsiType qType = qualifier.getType(); if (qType instanceof PsiClassType && !(qType instanceof GrMapType)) { PsiClassType.ClassResolveResult qResult = ((PsiClassType) qType).resolveGenerics(); PsiClass clazz = qResult.getElement(); if (clazz != null) { PsiClass mapClass = JavaPsiFacade.getInstance(refExpr.getProject()) .findClass(CommonClassNames.JAVA_UTIL_MAP, refExpr.getResolveScope()); if (mapClass != null && mapClass.getTypeParameters().length == 2) { PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor()); if (substitutor != null) { return TypeConversionUtil.erasure( substitutor.substitute(mapClass.getTypeParameters()[1])); } } } } } return null; }
private PsiType addBounds(PsiType substituted, final PsiTypeParameter typeParameter) { PsiElement captureContext = null; if (substituted instanceof PsiCapturedWildcardType) { final PsiCapturedWildcardType captured = (PsiCapturedWildcardType) substituted; substituted = captured.getWildcard(); captureContext = captured.getContext(); } if (substituted instanceof PsiWildcardType && !((PsiWildcardType) substituted).isSuper()) { PsiType originalBound = ((PsiWildcardType) substituted).getBound(); PsiManager manager = typeParameter.getManager(); final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); for (PsiType boundType : boundTypes) { PsiType substitutedBoundType = boundType.accept(mySimpleSubstitutionVisitor); PsiWildcardType wildcardType = (PsiWildcardType) substituted; if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) && !substitutedBoundType.equalsToText("java.lang.Object")) { if (originalBound == null || (!TypeConversionUtil.erasure(substitutedBoundType) .isAssignableFrom(TypeConversionUtil.erasure(originalBound)) && !TypeConversionUtil.erasure(substitutedBoundType) .isAssignableFrom( originalBound))) { // erasure is essential to avoid infinite recursion if (wildcardType.isExtends()) { final PsiType glb = GenericsUtil.getGreatestLowerBound(wildcardType.getBound(), substitutedBoundType); if (glb != null) { substituted = PsiWildcardType.createExtends(manager, glb); } } else { // unbounded substituted = PsiWildcardType.createExtends(manager, substitutedBoundType); } } } } } if (captureContext != null) { LOG.assertTrue(substituted instanceof PsiWildcardType); substituted = PsiCapturedWildcardType.create((PsiWildcardType) substituted, captureContext); } return substituted; }
private static PsiType doFun(GrReferenceExpression refExpr) { if (ResolveUtil.isClassReference(refExpr)) { GrExpression qualifier = refExpr.getQualifier(); LOG.assertTrue(qualifier != null); return TypesUtil.createJavaLangClassType( qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope()); } if (PsiUtil.isCompileStatic(refExpr)) { final GroovyResolveResult resolveResult = refExpr.advancedResolve(); final PsiElement resolvedF = resolveResult.getElement(); final PsiType type; if (resolvedF instanceof GrField) { type = ((GrField) resolvedF).getType(); } else if (resolvedF instanceof GrAccessorMethod) { type = ((GrAccessorMethod) resolvedF).getProperty().getType(); } else { type = null; } if (type != null) { return resolveResult.getSubstitutor().substitute(type); } } final PsiElement resolved = refExpr.resolve(); final PsiType nominal = refExpr.getNominalType(); Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr); if (reassigned != null && reassigned.booleanValue()) { return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true); } final PsiType inferred = getInferredTypes(refExpr, resolved); if (inferred == null) { if (nominal == null) { // inside nested closure we could still try to infer from variable initializer. Not sound, // but makes sense if (resolved instanceof GrVariable) { LOG.assertTrue(resolved.isValid()); return ((GrVariable) resolved).getTypeGroovy(); } } return nominal; } if (nominal == null) return inferred; if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) { if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) { return nominal; } } return inferred; }
@NotNull private MethodResolverProcessor createMethodProcessor( boolean allVariants, @Nullable String name, final boolean byShape, @Nullable GrExpression upToArgument) { final PsiType[] argTypes = PsiUtil.getArgumentTypes(this, false, upToArgument, byShape); if (byShape && argTypes != null) { for (int i = 0; i < argTypes.length; i++) { argTypes[i] = TypeConversionUtil.erasure(argTypes[i]); } } PsiType qualifierType = PsiImplUtil.getQualifierType(this); return new MethodResolverProcessor( name, this, false, qualifierType, argTypes, getTypeArguments(), allVariants, byShape); }
@SuppressWarnings({"HardCodedStringLiteral"}) private static void appendJVMSignature(JVMNameBuffer buffer, PsiType type) { if (type == null) { return; } final PsiType psiType = TypeConversionUtil.erasure(type); if (psiType instanceof PsiArrayType) { buffer.append(new JVMRawText("[")); appendJVMSignature(buffer, ((PsiArrayType) psiType).getComponentType()); } else if (psiType instanceof PsiClassType) { final JVMName jvmName = getJVMQualifiedName(psiType); appendJvmClassQualifiedName(buffer, jvmName); } else if (psiType instanceof PsiPrimitiveType) { buffer.append(getPrimitiveSignature(psiType.getCanonicalText())); } else { LOG.error("unknown type " + type.getCanonicalText()); } }
@NotNull private static PsiSubstitutor calculateMethodSubstitutor( @NotNull PsiTypeParameter[] typeParameters, @NotNull PsiMethod method, @NotNull PsiSubstitutor siteSubstitutor, @NotNull PsiType[] types1, @NotNull PsiType[] types2, @NotNull LanguageLevel languageLevel) { PsiSubstitutor substitutor = PsiResolveHelper.SERVICE .getInstance(method.getProject()) .inferTypeArguments(typeParameters, types1, types2, languageLevel); for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(method)) { ProgressManager.checkCanceled(); LOG.assertTrue(typeParameter != null); if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) { PsiType type = siteSubstitutor.substitute(typeParameter); if (type instanceof PsiClassType && typeParameter.getOwner() == method) { final PsiClass aClass = ((PsiClassType) type).resolve(); if (aClass instanceof PsiTypeParameter && ((PsiTypeParameter) aClass).getOwner() == method) { type = TypeConversionUtil.erasure(type, siteSubstitutor); } } substitutor = substitutor.put(typeParameter, type); } else { final PsiType type = substitutor.substitute(typeParameter); if (type instanceof PsiClassType) { final PsiClass aClass = ((PsiClassType) type).resolve(); if (aClass instanceof PsiTypeParameter) { substitutor = substitutor.put( typeParameter, JavaPsiFacade.getElementFactory(aClass.getProject()) .createType(aClass, siteSubstitutor)); } } } } return substitutor; }
@Nullable public PsiType fun(GrReferenceExpressionImpl refExpr) { PsiType result = GrReassignedLocalVarsChecker.checkReassignedVar(refExpr, true); if (result != null) return result; if (GrUnresolvedAccessInspection.isClassReference(refExpr)) { GrExpression qualifier = refExpr.getQualifier(); LOG.assertTrue(qualifier != null); return TypesUtil.createJavaLangClassType( qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope()); } final PsiElement resolved = refExpr.resolve(); final PsiType inferred = getInferredTypes(refExpr, resolved); final PsiType nominal = refExpr.getNominalType(); if (inferred == null || PsiType.NULL.equals(inferred)) { if (nominal == null) { // inside nested closure we could still try to infer from variable initializer. Not sound, // but makes sense if (resolved instanceof GrVariable) { LOG.assertTrue(resolved.isValid()); return ((GrVariable) resolved).getTypeGroovy(); } } return nominal; } if (nominal == null) return inferred; if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) { if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) { return nominal; } } return inferred; }
@Nullable private static PsiType getResultType( PsiMethodCallExpression call, PsiReferenceExpression methodExpression, JavaResolveResult result, @NotNull final LanguageLevel languageLevel) { final PsiMethod method = (PsiMethod) result.getElement(); if (method == null) return null; boolean is15OrHigher = languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0; final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType( call, methodExpression, method, new Condition<IElementType>() { @Override public boolean value(IElementType type) { return type != JavaElementType.CLASS; } }, languageLevel); if (getClassReturnType != null) { return getClassReturnType; } PsiType ret = method.getReturnType(); if (ret == null) return null; if (ret instanceof PsiClassType) { ret = ((PsiClassType) ret).setLanguageLevel(languageLevel); } if (is15OrHigher) { return captureReturnType(call, method, ret, result, languageLevel); } return TypeConversionUtil.erasure(ret); }
public static PsiType unboxPrimitiveTypeWrapperAndEraseGenerics(PsiType result) { return TypeConversionUtil.erasure(unboxPrimitiveTypeWrapper(result)); }
@NotNull public static GrImmediateClosureParameterImpl createErasedParameter(@NotNull PsiParameter param) { PsiType type = TypeConversionUtil.erasure(param.getType()); return new GrImmediateClosureParameterImpl( type, getParameterName(param), isParameterOptional(param), getDefaultInitializer(param)); }
// This methods works equally well for primary usages as well as for propagated callers' usages private static void fixActualArgumentsList( PsiExpressionList list, JavaChangeInfo changeInfo, boolean toInsertDefaultValue, PsiSubstitutor substitutor) throws IncorrectOperationException { final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); if (changeInfo.isParameterSetOrOrderChanged()) { if (changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl) changeInfo).isPropagationEnabled) { final ParameterInfoImpl[] createdParmsInfo = ((JavaChangeInfoImpl) changeInfo).getCreatedParmsInfoWithoutVarargs(); for (ParameterInfoImpl info : createdParmsInfo) { PsiExpression newArg; if (toInsertDefaultValue) { newArg = createDefaultValue(changeInfo, factory, info, list); } else { newArg = factory.createExpressionFromText(info.getName(), list); } JavaCodeStyleManager.getInstance(list.getProject()) .shortenClassReferences(list.add(newArg)); } } else { final PsiExpression[] args = list.getExpressions(); final int nonVarargCount = getNonVarargCount(changeInfo, args); final int varargCount = args.length - nonVarargCount; if (varargCount < 0) return; PsiExpression[] newVarargInitializers = null; final int newArgsLength; final int newNonVarargCount; final JavaParameterInfo[] newParms = changeInfo.getNewParameters(); if (changeInfo.isArrayToVarargs()) { newNonVarargCount = newParms.length - 1; final JavaParameterInfo lastNewParm = newParms[newParms.length - 1]; final PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()]; if (arrayToConvert instanceof PsiNewExpression) { final PsiNewExpression expression = (PsiNewExpression) arrayToConvert; final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer(); if (arrayInitializer != null) { newVarargInitializers = arrayInitializer.getInitializers(); } } newArgsLength = newVarargInitializers == null ? newParms.length : newNonVarargCount + newVarargInitializers.length; } else if (changeInfo.isRetainsVarargs()) { newNonVarargCount = newParms.length - 1; newArgsLength = newNonVarargCount + varargCount; } else if (changeInfo.isObtainsVarags()) { newNonVarargCount = newParms.length - 1; newArgsLength = newNonVarargCount; } else { newNonVarargCount = newParms.length; newArgsLength = newParms.length; } String[] oldVarargs = null; if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) { oldVarargs = new String[varargCount]; for (int i = nonVarargCount; i < args.length; i++) { oldVarargs[i - nonVarargCount] = args[i].getText(); } } final PsiExpression[] newArgs = new PsiExpression[newArgsLength]; for (int i = 0; i < newNonVarargCount; i++) { if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) { PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager()); if (type instanceof PsiArrayType) { type = substitutor.substitute(type); type = TypeConversionUtil.erasure(type); String typeText = type.getCanonicalText(); if (type instanceof PsiEllipsisType) { typeText = typeText.replace("...", "[]"); } String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}"; newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod()); continue; } } newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args); } if (changeInfo.isArrayToVarargs()) { if (newVarargInitializers == null) { newArgs[newNonVarargCount] = createActualArgument( changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); } else { System.arraycopy( newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length); } } else { final int newVarargCount = newArgsLength - newNonVarargCount; LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount); for (int i = newNonVarargCount; i < newArgsLength; i++) { final int oldIndex = newParms[newNonVarargCount].getOldIndex(); if (oldIndex >= 0 && oldIndex != nonVarargCount) { newArgs[i] = createActualArgument( changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); } else { System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount); break; } } } ChangeSignatureUtil.synchronizeList( list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm()); } } }
private Specifics isMoreSpecific( @NotNull MethodCandidateInfo info1, @NotNull MethodCandidateInfo info2, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel, @NotNull LanguageLevel languageLevel) { PsiMethod method1 = info1.getElement(); PsiMethod method2 = info2.getElement(); final PsiClass class1 = method1.getContainingClass(); final PsiClass class2 = method2.getContainingClass(); final PsiParameter[] params1 = method1.getParameterList().getParameters(); final PsiParameter[] params2 = method2.getParameterList().getParameters(); final PsiTypeParameter[] typeParameters1 = method1.getTypeParameters(); final PsiTypeParameter[] typeParameters2 = method2.getTypeParameters(); final PsiSubstitutor classSubstitutor1 = info1.getSubstitutor(false); // substitutions for method type parameters will be ignored final PsiSubstitutor classSubstitutor2 = info2.getSubstitutor(false); final int max = Math.max(params1.length, params2.length); PsiType[] types1 = PsiType.createArray(max); PsiType[] types2 = PsiType.createArray(max); final boolean varargsPosition = applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS; for (int i = 0; i < max; i++) { ProgressManager.checkCanceled(); PsiType type1 = params1.length > 0 ? params1[Math.min(i, params1.length - 1)].getType() : null; PsiType type2 = params2.length > 0 ? params2[Math.min(i, params2.length - 1)].getType() : null; if (varargsPosition) { if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType && params1.length == params2.length && class1 != null && (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType) type1) .getComponentType() .equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType) type2) .getComponentType() .equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { type1 = ((PsiEllipsisType) type1).toArrayType(); type2 = ((PsiEllipsisType) type2).toArrayType(); } else { type1 = type1 instanceof PsiEllipsisType ? ((PsiArrayType) type1).getComponentType() : type1; type2 = type2 instanceof PsiEllipsisType ? ((PsiArrayType) type2).getComponentType() : type2; } } types1[i] = type1; types2[i] = type2; } boolean sameBoxing = true; int[] boxingHappened = new int[2]; for (int i = 0; i < types1.length; i++) { ProgressManager.checkCanceled(); PsiType type1 = classSubstitutor1.substitute(types1[i]); PsiType type2 = classSubstitutor2.substitute(types2[i]); PsiType argType = i < getActualParameterTypes().length ? getActualParameterTypes()[i] : null; boolean boxingInFirst = false; if (isBoxingHappened(argType, type1, languageLevel)) { boxingHappened[0] += 1; boxingInFirst = true; } boolean boxingInSecond = false; if (isBoxingHappened(argType, type2, languageLevel)) { boxingHappened[1] += 1; boxingInSecond = true; } sameBoxing &= boxingInFirst == boxingInSecond; } if (boxingHappened[0] == 0 && boxingHappened[1] > 0) return Specifics.FIRST; if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND; if (sameBoxing) { final PsiSubstitutor siteSubstitutor1 = info1.getSiteSubstitutor(); final PsiSubstitutor siteSubstitutor2 = info2.getSiteSubstitutor(); final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2); final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1); final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor( typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel); boolean applicable12 = isApplicableTo( types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1, method2); final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor( typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel); boolean applicable21 = isApplicableTo( types1AtSite, method2, languageLevel, varargsPosition, methodSubstitutor2, method1); if (!myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { final boolean typeArgsApplicable12 = GenericsUtil.isTypeArgumentsApplicable( typeParameters1, methodSubstitutor1, myArgumentsList, !applicable21); final boolean typeArgsApplicable21 = GenericsUtil.isTypeArgumentsApplicable( typeParameters2, methodSubstitutor2, myArgumentsList, !applicable12); if (!typeArgsApplicable12) { applicable12 = false; } if (!typeArgsApplicable21) { applicable21 = false; } } if (applicable12 || applicable21) { if (applicable12 && !applicable21) return Specifics.SECOND; if (applicable21 && !applicable12) return Specifics.FIRST; final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT); final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT); if (abstract1 && !abstract2) { return Specifics.SECOND; } if (abstract2 && !abstract1) { return Specifics.FIRST; } } if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && myArgumentsList instanceof PsiExpressionList && (typeParameters1.length == 0 || typeParameters2.length == 0)) { boolean toCompareFunctional = false; if (types1.length > 0 && types2.length > 0) { for (int i = 0; i < getActualParametersLength(); i++) { final PsiType type1 = types1[Math.min(i, types1.length - 1)]; final PsiType type2 = types2[Math.min(i, types2.length - 1)]; // from 15.12.2.5 Choosing the Most Specific Method // In addition, a functional interface type S is more specific than a functional // interface type T for an expression exp // if T is not a subtype of S and one of the following conditions apply. if (LambdaUtil.isFunctionalType(type1) && !TypeConversionUtil.erasure(type1).isAssignableFrom(type2) && LambdaUtil.isFunctionalType(type2) && !TypeConversionUtil.erasure(type2).isAssignableFrom(type1)) { types1AtSite[Math.min(i, types1.length - 1)] = PsiType.NULL; types2AtSite[Math.min(i, types2.length - 1)] = PsiType.NULL; toCompareFunctional = true; } } } if (toCompareFunctional) { final boolean applicable12ignoreFunctionalType = isApplicableTo( types2AtSite, method1, languageLevel, varargsPosition, calculateMethodSubstitutor( typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel), null); final boolean applicable21ignoreFunctionalType = isApplicableTo( types1AtSite, method2, languageLevel, varargsPosition, calculateMethodSubstitutor( typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel), null); if (applicable12ignoreFunctionalType || applicable21ignoreFunctionalType) { Specifics specifics = null; for (int i = 0; i < getActualParametersLength(); i++) { if (types1AtSite[Math.min(i, types1.length - 1)] == PsiType.NULL && types2AtSite[Math.min(i, types2.length - 1)] == PsiType.NULL) { Specifics specific = isFunctionalTypeMoreSpecific( info1, info2, ((PsiExpressionList) myArgumentsList).getExpressions()[i], i); if (specific == Specifics.NEITHER) { specifics = Specifics.NEITHER; break; } if (specifics == null) { specifics = specific; } else if (specifics != specific) { specifics = Specifics.NEITHER; break; } } } if (!applicable12ignoreFunctionalType && applicable21ignoreFunctionalType) { return specifics == Specifics.FIRST ? Specifics.FIRST : Specifics.NEITHER; } if (!applicable21ignoreFunctionalType && applicable12ignoreFunctionalType) { return specifics == Specifics.SECOND ? Specifics.SECOND : Specifics.NEITHER; } return specifics; } } } } else if (varargsPosition) { final PsiType lastParamType1 = classSubstitutor1.substitute(types1[types1.length - 1]); final PsiType lastParamType2 = classSubstitutor2.substitute(types2[types1.length - 1]); final boolean assignable1 = TypeConversionUtil.isAssignable(lastParamType2, lastParamType1); final boolean assignable2 = TypeConversionUtil.isAssignable(lastParamType1, lastParamType2); if (assignable1 && !assignable2) { return Specifics.FIRST; } if (assignable2 && !assignable1) { return Specifics.SECOND; } } if (class1 != class2) { if (class2.isInheritor(class1, true) || class1.isInterface() && !class2.isInterface()) { if (MethodSignatureUtil.isSubsignature( method1.getSignature(info1.getSubstitutor(false)), method2.getSignature(info2.getSubstitutor(false)))) { return Specifics.SECOND; } else if (method1.hasModifierProperty(PsiModifier.STATIC) && method2.hasModifierProperty(PsiModifier.STATIC) && boxingHappened[0] == 0) { return Specifics.SECOND; } } else if (MethodSignatureUtil.areErasedParametersEqual( method1.getSignature(PsiSubstitutor.EMPTY), method2.getSignature(PsiSubstitutor.EMPTY)) && MethodSignatureUtil.isSubsignature( method2.getSignature(info2.getSubstitutor(false)), method1.getSignature(info1.getSubstitutor(false)))) { return Specifics.FIRST; } else if (class1.isInheritor(class2, true) || class2.isInterface()) { if (method1.hasModifierProperty(PsiModifier.STATIC) && method2.hasModifierProperty(PsiModifier.STATIC) && boxingHappened[0] == 0) { return Specifics.FIRST; } } } final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1); final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2); if (raw1 ^ raw2) { return raw1 ? Specifics.SECOND : Specifics.FIRST; } final boolean varargs1 = info1.isVarargs(); final boolean varargs2 = info2.isVarargs(); if (varargs1 ^ varargs2) { return varargs1 ? Specifics.SECOND : Specifics.FIRST; } return Specifics.NEITHER; }
public static boolean isAcceptable( PsiLambdaExpression lambdaExpression, final PsiType leftType, boolean checkReturnType) { if (leftType instanceof PsiIntersectionType) { for (PsiType conjunctType : ((PsiIntersectionType) leftType).getConjuncts()) { if (isAcceptable(lambdaExpression, conjunctType, checkReturnType)) return true; } return false; } final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(leftType)); final PsiClass psiClass = resolveResult.getElement(); if (psiClass instanceof PsiAnonymousClass) { return isAcceptable( lambdaExpression, ((PsiAnonymousClass) psiClass).getBaseClassType(), checkReturnType); } final MethodSignature methodSignature = getFunction(psiClass); if (methodSignature == null) return false; final PsiParameter[] lambdaParameters = lambdaExpression.getParameterList().getParameters(); final PsiType[] parameterTypes = methodSignature.getParameterTypes(); if (lambdaParameters.length != parameterTypes.length) return false; for (int lambdaParamIdx = 0, length = lambdaParameters.length; lambdaParamIdx < length; lambdaParamIdx++) { PsiParameter parameter = lambdaParameters[lambdaParamIdx]; final PsiTypeElement typeElement = parameter.getTypeElement(); if (typeElement != null) { final PsiType lambdaFormalType = typeElement.getType(); final PsiType methodParameterType = parameterTypes[lambdaParamIdx]; if (lambdaFormalType instanceof PsiPrimitiveType) { if (methodParameterType instanceof PsiPrimitiveType) return methodParameterType.equals(lambdaFormalType); return false; } if (!TypeConversionUtil.erasure(lambdaFormalType) .isAssignableFrom( TypeConversionUtil.erasure( GenericsUtil.eliminateWildcards( resolveResult .getSubstitutor() .substitute( methodSignature .getSubstitutor() .substitute(methodParameterType)))))) { return false; } } } if (checkReturnType) { final String uniqueVarName = JavaCodeStyleManager.getInstance(lambdaExpression.getProject()) .suggestUniqueVariableName("l", lambdaExpression, true); String canonicalText = leftType.getCanonicalText(); if (leftType instanceof PsiEllipsisType) { canonicalText = ((PsiEllipsisType) leftType).toArrayType().getCanonicalText(); } final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(lambdaExpression.getProject()) .createStatementFromText( canonicalText + " " + uniqueVarName + " = " + lambdaExpression.getText(), lambdaExpression); final PsiLocalVariable localVariable = (PsiLocalVariable) ((PsiDeclarationStatement) assignmentFromText).getDeclaredElements()[0]; LOG.assertTrue(psiClass != null); PsiType methodReturnType = getReturnType(psiClass, methodSignature); if (methodReturnType != null) { methodReturnType = resolveResult .getSubstitutor() .substitute(methodSignature.getSubstitutor().substitute(methodReturnType)); return LambdaHighlightingUtil.checkReturnTypeCompatible( (PsiLambdaExpression) localVariable.getInitializer(), methodReturnType) == null; } } return true; }
// method1 has more general parameter types thn method2 private boolean secondMethodIsPreferable( @NotNull PsiMethod method1, @NotNull PsiSubstitutor substitutor1, @Nullable PsiElement resolveContext1, @NotNull PsiMethod method2, @NotNull PsiSubstitutor substitutor2, @Nullable PsiElement resolveContext2) { if (!method1.getName().equals(method2.getName())) return false; final Boolean custom = GrMethodComparator.checkDominated(method1, substitutor1, method2, substitutor2, this); if (custom != null) return custom; PsiType[] argTypes = myArgumentTypes; if (method1 instanceof GrGdkMethod && method2 instanceof GrGdkMethod) { method1 = ((GrGdkMethod) method1).getStaticMethod(); method2 = ((GrGdkMethod) method2).getStaticMethod(); if (myArgumentTypes != null) { argTypes = PsiType.createArray(argTypes.length + 1); System.arraycopy(myArgumentTypes, 0, argTypes, 1, myArgumentTypes.length); argTypes[0] = myThisType; } } if (myIsConstructor && argTypes != null && argTypes.length == 1) { if (method1.getParameterList().getParametersCount() == 0) return true; if (method2.getParameterList().getParametersCount() == 0) return false; } PsiParameter[] params1 = method1.getParameterList().getParameters(); PsiParameter[] params2 = method2.getParameterList().getParameters(); if (argTypes == null && params1.length != params2.length) return false; if (params1.length < params2.length) { if (params1.length == 0) return false; final PsiType lastType = params1[params1.length - 1].getType(); // varargs applicability return lastType instanceof PsiArrayType; } for (int i = 0; i < params2.length; i++) { final PsiType ptype1 = params1[i].getType(); final PsiType ptype2 = params2[i].getType(); PsiType type1 = substitutor1.substitute(ptype1); PsiType type2 = substitutor2.substitute(ptype2); if (argTypes != null && argTypes.length > i) { PsiType argType = argTypes[i]; if (argType != null) { final boolean converts1 = TypesUtil.isAssignableWithoutConversions( TypeConversionUtil.erasure(type1), argType, myPlace); final boolean converts2 = TypesUtil.isAssignableWithoutConversions( TypeConversionUtil.erasure(type2), argType, myPlace); if (converts1 != converts2) { return converts2; } // see groovy.lang.GroovyCallable if (TypesUtil.resolvesTo(type1, CommonClassNames.JAVA_UTIL_CONCURRENT_CALLABLE) && TypesUtil.resolvesTo(type2, CommonClassNames.JAVA_LANG_RUNNABLE)) { if (InheritanceUtil.isInheritor( argType, GroovyCommonClassNames.GROOVY_LANG_GROOVY_CALLABLE)) return true; } } } if (!typesAgree(TypeConversionUtil.erasure(ptype1), TypeConversionUtil.erasure(ptype2))) return false; if (resolveContext1 != null && resolveContext2 == null) { return !(TypesUtil.resolvesTo(type1, CommonClassNames.JAVA_LANG_OBJECT) && TypesUtil.resolvesTo(type2, CommonClassNames.JAVA_LANG_OBJECT)); } if (resolveContext1 == null && resolveContext2 != null) { return true; } } if (!(method1 instanceof SyntheticElement) && !(method2 instanceof SyntheticElement)) { final PsiType returnType1 = substitutor1.substitute(method1.getReturnType()); final PsiType returnType2 = substitutor2.substitute(method2.getReturnType()); if (!TypesUtil.isAssignableWithoutConversions(returnType1, returnType2, myPlace) && TypesUtil.isAssignableWithoutConversions(returnType2, returnType1, myPlace)) { return false; } } return true; }
private static PsiMethod generateDelegateMethod( PsiMethod method, PsiClass superClass, PsiSubstitutor substitutor, boolean keepParameterAnnotations) { final LightMethodBuilder builder = new LightMethodBuilder( superClass.getManager(), GroovyFileType.GROOVY_LANGUAGE, method.getName()); builder.setContainingClass(superClass); builder.setMethodReturnType(substitutor.substitute(method.getReturnType())); builder.setNavigationElement(method); builder.addModifier(PsiModifier.PUBLIC); final PsiTypeParameter[] typeParameters = method.getTypeParameters(); final PsiClass containingClass = method.getContainingClass(); boolean isRaw = containingClass != null && PsiUtil.isRawSubstitutor(containingClass, substitutor); if (isRaw) { substitutor = JavaPsiFacade.getInstance(method.getProject()) .getElementFactory() .createRawSubstitutor(substitutor, typeParameters); } if (!isRaw) { for (PsiTypeParameter typeParameter : typeParameters) { builder.addTypeParameter(typeParameter); } } final PsiParameter[] originalParameters = method.getParameterList().getParameters(); for (int i = 0; i < originalParameters.length; i++) { PsiParameter originalParameter = originalParameters[i]; PsiType type; if (isRaw) { type = TypeConversionUtil.erasure(substitutor.substitute(originalParameter.getType())); } else { type = substitutor.substitute(originalParameter.getType()); } if (type == null) { type = PsiType.getJavaLangObject(superClass.getManager(), superClass.getResolveScope()); } final LightParameter lightParameter = new LightParameter( StringUtil.notNullize(originalParameter.getName(), "p" + i), type, builder, JavaLanguage.INSTANCE); if (keepParameterAnnotations) { final PsiCompositeModifierList delegatingModifierList = new PsiCompositeModifierList( method.getManager(), Collections.singletonList(originalParameter.getModifierList())); lightParameter.setModifierList(delegatingModifierList); } builder.addParameter(lightParameter); } builder.setBaseIcon(JetgroovyIcons.Groovy.Method); return new DelegatedMethod(builder, method); }
private PsiType getCategoryTargetType(PsiMethod method) { final PsiType parameterType = method.getParameterList().getParameters()[0].getType(); return TypesUtil.boxPrimitiveType( TypeConversionUtil.erasure(parameterType), myPsiManager, myScope); }