private static PsiType doGetType(PsiBinaryExpressionImpl param) { PsiExpression lOperand = param.getLOperand(); PsiExpression rOperand = param.getROperand(); if (rOperand == null) return null; PsiType rType = rOperand.getType(); IElementType sign = param.getOperationTokenType(); // optimization: if we can calculate type based on right type only PsiType type = TypeConversionUtil.calcTypeForBinaryExpression(null, rType, sign, false); if (type != TypeConversionUtil.NULL_TYPE) return type; if (lOperand instanceof PsiBinaryExpressionImpl && !JavaResolveCache.getInstance(param.getProject()).isTypeCached(lOperand)) { // cache all intermediate expression types from bottom up PsiBinaryExpressionImpl topLevel = param; PsiElement element = param; while (element instanceof PsiBinaryExpressionImpl) { topLevel = (PsiBinaryExpressionImpl) element; element = element.getParent(); } topLevel.accept( new JavaRecursiveElementWalkingVisitor() { @Override protected void elementFinished(PsiElement element) { if (element instanceof PsiExpression) { ProgressIndicatorProvider.checkCanceled(); ((PsiExpression) element).getType(); } } }); } PsiType lType = lOperand.getType(); return TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, sign, true); }
@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 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; }
private void checkExpression(PsiExpression expression) { if (expression.getParent() instanceof PsiParenthesizedExpression) { return; } final PsiType expressionType = expression.getType(); if (expressionType == null) { return; } if (expressionType.getArrayDimensions() > 0) { // a horrible hack to get around what happens when you pass // an array to a vararg expression return; } if (TypeConversionUtil.isPrimitiveAndNotNull(expressionType)) { return; } final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(expressionType); if (unboxedType == null) { return; } final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); if (expectedType == null) { return; } if (!TypeConversionUtil.isPrimitiveAndNotNull(expectedType)) { return; } if (!expectedType.isAssignableFrom(unboxedType)) { return; } registerError(expression, expression); }
@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 public static PsiType getLeastUpperBound(PsiType type1, PsiType type2, PsiManager manager) { if (TypeConversionUtil.isPrimitiveAndNotNull(type1) || TypeConversionUtil.isPrimitiveAndNotNull(type2)) return null; if (TypeConversionUtil.isNullType(type1)) return type2; if (TypeConversionUtil.isNullType(type2)) return type1; if (Comparing.equal(type1, type2)) return type1; return getLeastUpperBound(type1, type2, new LinkedHashSet<Pair<PsiType, PsiType>>(), manager); }
private static boolean changeClassTypeArgument( PsiMethod myMethod, Project project, PsiType superReturnType, PsiClass superClass, Editor editor, PsiType returnType) { if (superClass == null || !superClass.hasTypeParameters()) return true; final PsiClass superReturnTypeClass = PsiUtil.resolveClassInType(superReturnType); if (superReturnTypeClass == null || !(superReturnTypeClass instanceof PsiTypeParameter || superReturnTypeClass.hasTypeParameters())) return true; final PsiClass derivedClass = myMethod.getContainingClass(); if (derivedClass == null) return true; final PsiReferenceParameterList referenceParameterList = findTypeArgumentsList(superClass, derivedClass); if (referenceParameterList == null) return true; final PsiElement resolve = ((PsiJavaCodeReferenceElement) referenceParameterList.getParent()).resolve(); if (!(resolve instanceof PsiClass)) return true; final PsiClass baseClass = (PsiClass) resolve; if (returnType instanceof PsiPrimitiveType) { returnType = ((PsiPrimitiveType) returnType).getBoxedType(derivedClass); } final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, baseClass, PsiSubstitutor.EMPTY); final PsiType superReturnTypeInBaseClassType = superClassSubstitutor.substitute(superReturnType); final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper(); final PsiSubstitutor psiSubstitutor = resolveHelper.inferTypeArguments( PsiTypesUtil.filterUnusedTypeParameters( superReturnTypeInBaseClassType, baseClass.getTypeParameters()), new PsiType[] {superReturnTypeInBaseClassType}, new PsiType[] {returnType}, PsiUtil.getLanguageLevel(superClass)); final TypeMigrationRules rules = new TypeMigrationRules(); final PsiSubstitutor compoundSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, derivedClass, PsiSubstitutor.EMPTY) .putAll(psiSubstitutor); rules.setBoundScope(new LocalSearchScope(derivedClass)); TypeMigrationProcessor.runHighlightingTypeMigration( project, editor, rules, referenceParameterList, JavaPsiFacade.getElementFactory(project).createType(baseClass, compoundSubstitutor)); return false; }
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 @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; }
private boolean isOverridden( PsiClass inheritor, PsiMethod method, PsiMethod superMethod, PsiClass superInterface) { // calculate substitutor of containingClass --> inheritor PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor( myContainingClass, inheritor, PsiSubstitutor.EMPTY); // calculate substitutor of inheritor --> superInterface substitutor = TypeConversionUtil.getSuperClassSubstitutor(superInterface, inheritor, substitutor); return MethodSignatureUtil.isSubsignature( superMethod.getSignature(substitutor), method.getSignature(PsiSubstitutor.EMPTY)); }
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; }
public static PsiType eliminateWildcards(PsiType type, final boolean eliminateInTypeArguments) { if (eliminateInTypeArguments && type instanceof PsiClassType) { PsiClassType classType = (PsiClassType) type; JavaResolveResult resolveResult = classType.resolveGenerics(); PsiClass aClass = (PsiClass) resolveResult.getElement(); if (aClass != null) { PsiManager manager = aClass.getManager(); PsiTypeParameter[] typeParams = aClass.getTypeParameters(); Map<PsiTypeParameter, PsiType> map = new HashMap<PsiTypeParameter, PsiType>(); for (PsiTypeParameter typeParam : typeParams) { PsiType substituted = resolveResult.getSubstitutor().substitute(typeParam); if (substituted instanceof PsiWildcardType) { substituted = ((PsiWildcardType) substituted).getBound(); if (substituted == null) substituted = TypeConversionUtil.typeParameterErasure(typeParam); } map.put(typeParam, substituted); } PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); PsiSubstitutor substitutor = factory.createSubstitutor(map); type = factory.createType(aClass, substitutor); } } else if (type instanceof PsiArrayType) { return eliminateWildcards(((PsiArrayType) type).getComponentType(), false).createArrayType(); } else if (type instanceof PsiWildcardType) { final PsiType bound = ((PsiWildcardType) type).getBound(); return bound != null ? bound : ((PsiWildcardType) type).getExtendsBound(); // object } else if (type instanceof PsiCapturedWildcardType && !eliminateInTypeArguments) { return eliminateWildcards( ((PsiCapturedWildcardType) type).getWildcard(), eliminateInTypeArguments); } return type; }
private static void addDefaultConstructor( JavaChangeInfo changeInfo, PsiClass aClass, final UsageInfo[] usages) throws IncorrectOperationException { if (!(aClass instanceof PsiAnonymousClass)) { PsiElementFactory factory = JavaPsiFacade.getElementFactory(aClass.getProject()); PsiMethod defaultConstructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass); defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(aClass.getProject()).reformat(defaultConstructor); defaultConstructor = (PsiMethod) aClass.add(defaultConstructor); PsiUtil.setModifierProperty( defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true); addSuperCall(changeInfo, defaultConstructor, null, usages); } else { final PsiElement parent = aClass.getParent(); if (parent instanceof PsiNewExpression) { final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList(); final PsiClass baseClass = changeInfo.getMethod().getContainingClass(); final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY); fixActualArgumentsList(argumentList, changeInfo, true, substitutor); } } }
public static boolean isNumericType(@Nullable PsiType type) { if (type instanceof PsiClassType) { return TYPE_TO_RANK.contains(type.getCanonicalText()); } return type instanceof PsiPrimitiveType && TypeConversionUtil.isNumericType(type); }
/* Guesswork */ @Nullable private static PsiSubstitutor getInheritorSubstitutorForNewExpression( final PsiClass baseClass, final PsiClass inheritor, final PsiSubstitutor baseSubstitutor, final PsiElement context) { final Project project = baseClass.getProject(); JavaPsiFacade facade = JavaPsiFacade.getInstance(project); final PsiResolveHelper resolveHelper = facade.getResolveHelper(); PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(baseClass, inheritor, PsiSubstitutor.EMPTY); if (superSubstitutor == null) return null; PsiSubstitutor inheritorSubstitutor = PsiSubstitutor.EMPTY; for (PsiTypeParameter inheritorParameter : PsiUtil.typeParametersIterable(inheritor)) { for (PsiTypeParameter baseParameter : PsiUtil.typeParametersIterable(baseClass)) { final PsiType substituted = superSubstitutor.substitute(baseParameter); PsiType arg = baseSubstitutor.substitute(baseParameter); if (arg instanceof PsiWildcardType) arg = ((PsiWildcardType) arg).getBound(); PsiType substitution = resolveHelper.getSubstitutionForTypeParameter( inheritorParameter, substituted, arg, true, PsiUtil.getLanguageLevel(context)); if (PsiType.NULL.equals(substitution)) continue; if (substitution == null) { return facade.getElementFactory().createRawSubstitutor(inheritor); } inheritorSubstitutor = inheritorSubstitutor.put(inheritorParameter, substitution); break; } } return inheritorSubstitutor; }
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)); } } }
private static void addInheritors( CompletionParameters parameters, final CompletionResultSet resultSet, final PsiClass referencedClass, final int parameterIndex) { final List<PsiClassType> typeList = Collections.singletonList( (PsiClassType) TypeConversionUtil.typeParameterErasure( referencedClass.getTypeParameters()[parameterIndex])); JavaInheritorsGetter.processInheritors( parameters, typeList, resultSet.getPrefixMatcher(), new Consumer<PsiType>() { @Override public void consume(final PsiType type) { final PsiClass psiClass = PsiUtil.resolveClassInType(type); if (psiClass == null) return; resultSet.addElement( TailTypeDecorator.withTail( new JavaPsiClassReferenceElement(psiClass), getTail(parameterIndex == referencedClass.getTypeParameters().length - 1))); } }); }
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 Set<PsiType> flatten(PsiType[] conjuncts, Set<PsiType> types) { for (PsiType conjunct : conjuncts) { if (conjunct instanceof PsiIntersectionType) { PsiIntersectionType type = (PsiIntersectionType) conjunct; flatten(type.getConjuncts(), types); } else { types.add(conjunct); } } if (types.size() > 1) { PsiType[] array = types.toArray(createArray(types.size())); for (Iterator<PsiType> iterator = types.iterator(); iterator.hasNext(); ) { PsiType type = iterator.next(); for (PsiType existing : array) { if (type != existing) { final boolean allowUncheckedConversion = type instanceof PsiClassType && ((PsiClassType) type).isRaw(); if (TypeConversionUtil.isAssignable(type, existing, allowUncheckedConversion)) { iterator.remove(); break; } } } } if (types.isEmpty()) { types.add(array[0]); } } return types; }
private JavaResolveResult advancedResolveImpl() { final PsiElement resolve = resolveElement(); if (resolve instanceof PsiClass) { final Map<PsiTypeParameter, PsiType> substitutionMap = new HashMap<PsiTypeParameter, PsiType>(); int index = 0; for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable((PsiClass) resolve)) { if (index >= myTypeParameters.length) { final PsiTypeParameterListOwner parameterOwner = parameter.getOwner(); if (parameterOwner == resolve) { substitutionMap.put(parameter, null); } else if (parameterOwner instanceof PsiClass) { PsiElement containingClass = myParent; while ((containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class, true)) != null) { final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getClassSubstitutor( (PsiClass) parameterOwner, (PsiClass) containingClass, PsiSubstitutor.EMPTY); if (superClassSubstitutor != null) { substitutionMap.put(parameter, superClassSubstitutor.substitute(parameter)); break; } } } } else { substitutionMap.put(parameter, myTypeParameters[index].getType()); } index++; } return new CandidateInfo(resolve, PsiSubstitutorImpl.createSubstitutor(substitutionMap)); } else { return new CandidateInfo(resolve, PsiSubstitutor.EMPTY); } }
/** * Adds all code methods of clazz add its super classes to signatures. Doesn't walk into * interfaces because all methods from them will be overloaded in any case. Besides Some of * interfaces came from delegates and they should be visited during the following processing. * * @param clazz current class * @param substitutor super class substitutor of clazz * @param signatures map to initialize * @param classes already visited classes */ private static void initializeSignatures( PsiClass clazz, PsiSubstitutor substitutor, Map<MethodSignature, PsiMethod> signatures, Set<PsiClass> classes) { if (clazz.isInterface()) return; if (classes.add(clazz)) { final List<PsiMethod> methods; if (clazz instanceof GrTypeDefinition) { methods = new ArrayList<PsiMethod>(); GrClassImplUtil.collectMethodsFromBody((GrTypeDefinition) clazz, methods); } else { methods = Arrays.asList(clazz.getMethods()); } for (PsiMethod method : methods) { addMethodChecked(signatures, method, substitutor, null); } for (PsiClassType type : getSuperTypes(clazz)) { final PsiClassType.ClassResolveResult result = type.resolveGenerics(); final PsiClass superClass = result.getElement(); if (superClass == null) continue; final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, clazz, substitutor); initializeSignatures(superClass, superClassSubstitutor, signatures, classes); } } }
@Nullable private PsiAnnotation findNullabilityAnnotation( @NotNull PsiModifierListOwner owner, boolean checkBases, boolean nullable) { Set<String> qNames = ContainerUtil.newHashSet(nullable ? getNullables() : getNotNulls()); PsiAnnotation annotation = checkBases && (owner instanceof PsiClass || owner instanceof PsiMethod) ? AnnotationUtil.findAnnotationInHierarchy(owner, qNames) : AnnotationUtil.findAnnotation(owner, qNames); if (annotation != null) { return annotation; } if (owner instanceof PsiParameter && !TypeConversionUtil.isPrimitiveAndNotNull(((PsiParameter) owner).getType())) { // even if javax.annotation.Nullable is not configured, it should still take precedence over // ByDefault annotations if (AnnotationUtil.isAnnotated( owner, nullable ? Arrays.asList(DEFAULT_NOT_NULLS) : Arrays.asList(DEFAULT_NULLABLES), checkBases, false)) { return null; } return findContainerAnnotation( owner, nullable ? "javax.annotation.ParametersAreNullableByDefault" : "javax.annotation.ParametersAreNonnullByDefault"); } return null; }
@NotNull private static List<PsiMethod> findMethodsBySignature( @NotNull PsiClass aClass, @NotNull PsiMethod patternMethod, boolean checkBases, boolean stopOnFirst) { final PsiMethod[] methodsByName = aClass.findMethodsByName(patternMethod.getName(), checkBases); if (methodsByName.length == 0) return Collections.emptyList(); final List<PsiMethod> methods = new SmartList<PsiMethod>(); final MethodSignature patternSignature = patternMethod.getSignature(PsiSubstitutor.EMPTY); for (final PsiMethod method : methodsByName) { final PsiClass superClass = method.getContainingClass(); final PsiSubstitutor substitutor; if (checkBases && !aClass.equals(superClass)) { substitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY); } else { substitutor = PsiSubstitutor.EMPTY; } final MethodSignature signature = method.getSignature(substitutor); if (signature.equals(patternSignature)) { methods.add(method); if (stopOnFirst) { break; } } } return methods; }
@Override public boolean isMemberEnabled(MemberInfo member) { final PsiClass currentSuperClass = getSuperClass(); if (currentSuperClass == null) return true; if (myMemberInfoStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member)) return false; if (myMemberInfoStorage.getExtending(currentSuperClass).contains(member.getMember())) return false; final boolean isInterface = currentSuperClass.isInterface(); if (!isInterface) return true; PsiElement element = member.getMember(); if (element instanceof PsiClass && ((PsiClass) element).isInterface()) return true; if (element instanceof PsiField) { return ((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC); } if (element instanceof PsiMethod) { final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor( currentSuperClass, myClass, PsiSubstitutor.EMPTY); final MethodSignature signature = ((PsiMethod) element).getSignature(superSubstitutor); final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(currentSuperClass, signature, false); if (superClassMethod != null && !PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) return false; return !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC) || PsiUtil.isLanguageLevel8OrHigher(currentSuperClass); } return true; }
private static PsiSubstitutor calculateSubstitutor( PsiMethod derivedMethod, PsiMethod baseMethod) { PsiSubstitutor substitutor; if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) { substitutor = PsiSubstitutor.EMPTY; } else { final PsiClass baseClass = baseMethod.getContainingClass(); final PsiClass derivedClass = derivedMethod.getContainingClass(); if (baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) { final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor( baseClass, derivedClass, PsiSubstitutor.EMPTY); final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor); final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor( methodSignature, superMethodSignature); substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor; } else { substitutor = PsiSubstitutor.EMPTY; } } return substitutor; }
public void testEnum() throws Exception { setupLoadingFilter(); final PsiClass enumClass = myJavaFacade.findClass("enums.OurEnum", GlobalSearchScope.moduleScope(myModule)); assertNotNull(enumClass); assertTrue(enumClass.isEnum()); final PsiClass superClass = enumClass.getSuperClass(); assertNotNull(superClass); assertEquals("java.lang.Enum", superClass.getQualifiedName()); assertTrue(enumClass.isInheritor(superClass, false)); final PsiClassType[] superTypes = enumClass.getSuperTypes(); assertEquals(1, superTypes.length); assertEquals("java.lang.Enum<enums.OurEnum>", superTypes[0].getCanonicalText()); final PsiClass[] supers = enumClass.getSupers(); assertEquals(1, supers.length); assertEquals("java.lang.Enum", supers[0].getQualifiedName()); final PsiClassType[] extendsListTypes = enumClass.getExtendsListTypes(); assertEquals(1, extendsListTypes.length); assertEquals("java.lang.Enum<enums.OurEnum>", extendsListTypes[0].getCanonicalText()); final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, enumClass, PsiSubstitutor.EMPTY); assertEquals( "java.lang.Enum<enums.OurEnum>", myJavaFacade .getElementFactory() .createType(superClass, superClassSubstitutor) .getCanonicalText()); teardownLoadingFilter(); }
public static String checkReturnType( PsiMethodReferenceExpression expression, JavaResolveResult result, PsiType functionalInterfaceType) { final PsiElement resolve = result.getElement(); if (resolve instanceof PsiMethod) { final PsiClass containingClass = ((PsiMethod) resolve).getContainingClass(); LOG.assertTrue(containingClass != null); PsiSubstitutor subst = result.getSubstitutor(); PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass(); if (qContainingClass != null && isReceiverType(functionalInterfaceType, containingClass, (PsiMethod) resolve)) { subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst); LOG.assertTrue(subst != null); } final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType); PsiType returnType = PsiTypesUtil.patchMethodGetClassReturnType( expression, expression, (PsiMethod) resolve, null, PsiUtil.getLanguageLevel(expression)); if (returnType == null) { returnType = ((PsiMethod) resolve).getReturnType(); } PsiType methodReturnType = subst.substitute(returnType); if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) { if (methodReturnType == null) { methodReturnType = JavaPsiFacade.getElementFactory(expression.getProject()) .createType(containingClass, subst); } if (!TypeConversionUtil.isAssignable(interfaceReturnType, methodReturnType, false)) { return "Bad return type in method reference: cannot convert " + methodReturnType.getCanonicalText() + " to " + interfaceReturnType.getCanonicalText(); } } } return null; }
@Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { return myType.isValid() && myExpression.isValid() && myExpression.getManager().isInProject(myExpression) && !TypeConversionUtil.isPrimitiveAndNotNull(myType) && (myType instanceof PsiArrayType || myExpression.getArgumentList() != null); }