private Binding unify(final PsiType x, final PsiType y, final Unifier unifier) { final int indicator = (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0); switch (indicator) { case 0: if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) { return unifier.unify(x, y); } else if (x instanceof PsiArrayType || y instanceof PsiArrayType) { final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType) x).getComponentType() : x; final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType) y).getComponentType() : y; return unify(xType, yType, unifier); } else if (x instanceof PsiClassType && y instanceof PsiClassType) { final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); final PsiClass xClass = resultX.getElement(); final PsiClass yClass = resultY.getElement(); if (xClass != null && yClass != null) { final PsiSubstitutor ySubst = resultY.getSubstitutor(); final PsiSubstitutor xSubst = resultX.getSubstitutor(); if (!xClass.equals(yClass)) { return null; } Binding b = create(); for (final PsiTypeParameter aParm : xSubst.getSubstitutionMap().keySet()) { final PsiType xType = xSubst.substitute(aParm); final PsiType yType = ySubst.substitute(aParm); final Binding b1 = unify(xType, yType, unifier); if (b1 == null) { return null; } b = b.compose(b1); } return b; } } else if (y instanceof Bottom) { return create(); } else { return null; } default: return unifier.unify(x, y); } }
@Nullable public static PsiType getExpectedClosureReturnType(GrClosableBlock closure) { final Set<PsiType> expectedTypes = getDefaultExpectedTypes(closure); List<PsiType> expectedReturnTypes = new ArrayList<PsiType>(); for (PsiType expectedType : expectedTypes) { if (!(expectedType instanceof PsiClassType)) return null; final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType) expectedType).resolveGenerics(); final PsiClass resolved = resolveResult.getElement(); if (resolved == null || !(GroovyCommonClassNames.GROOVY_LANG_CLOSURE.equals(resolved.getQualifiedName()))) return null; final PsiTypeParameter[] typeParameters = resolved.getTypeParameters(); if (typeParameters.length != 1) return null; final PsiTypeParameter expected = typeParameters[0]; final PsiType expectedReturnType = resolveResult.getSubstitutor().substitute(expected); if (expectedReturnType == PsiType.VOID || expectedReturnType == null) return null; expectedReturnTypes.add(expectedReturnType); } return TypesUtil.getLeastUpperBoundNullable(expectedReturnTypes, closure.getManager()); }
@Nullable private static PsiType getExpectedTypeArg( PsiElement context, int index, PsiClassType.ClassResolveResult expectedType, PsiSubstitutor currentSubstitutor, PsiTypeParameter[] params) { PsiClass expectedClass = expectedType.getElement(); assert expectedClass != null; for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) { final PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter); final PsiType paramSubstitution = currentSubstitutor.substitute(parameter); final PsiType substitution = JavaPsiFacade.getInstance(context.getProject()) .getResolveHelper() .getSubstitutionForTypeParameter( params[index], paramSubstitution, argSubstitution, false, PsiUtil.getLanguageLevel(context)); if (substitution != null && substitution != PsiType.NULL) { return substitution; } } return null; }
private void getVariantsFromQualifierType( @NotNull PsiType qualifierType, @NotNull Project project) { final ResolveState state = ResolveState.initial(); if (qualifierType instanceof PsiClassType) { PsiClassType.ClassResolveResult result = ((PsiClassType) qualifierType).resolveGenerics(); PsiClass qualifierClass = result.getElement(); if (qualifierClass != null) { qualifierClass.processDeclarations( myProcessor, state.put(PsiSubstitutor.KEY, result.getSubstitutor()), null, myRefExpr); } } else if (qualifierType instanceof PsiArrayType) { final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project) .getArrayClass(((PsiArrayType) qualifierType).getComponentType()); if (arrayClass != null) { if (!arrayClass.processDeclarations(myProcessor, state, null, myRefExpr)) return; } } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) { getVariantsFromQualifierType(conjunct, project); } return; } ResolveUtil.processNonCodeMembers(qualifierType, myProcessor, myRefExpr, state); }
@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; }
public static void register( final HighlightInfo highlightInfo, PsiExpression expression, final PsiType lType) { expression = PsiUtil.deparenthesizeExpression(expression); if (!(expression instanceof PsiNewExpression)) return; final PsiType rType = expression.getType(); PsiType newType = lType; if (rType instanceof PsiClassType && newType instanceof PsiClassType) { final PsiClassType.ClassResolveResult rResolveResult = ((PsiClassType) rType).resolveGenerics(); final PsiClass rClass = rResolveResult.getElement(); if (rClass != null) { final PsiClassType.ClassResolveResult lResolveResult = ((PsiClassType) newType).resolveGenerics(); final PsiClass lClass = lResolveResult.getElement(); if (lClass != null) { PsiSubstitutor substitutor = getInheritorSubstitutorForNewExpression( lClass, rClass, lResolveResult.getSubstitutor(), expression); if (substitutor != null) { newType = JavaPsiFacade.getInstance(lClass.getProject()) .getElementFactory() .createType(rClass, substitutor); } } } } PsiNewExpression newExpression = (PsiNewExpression) expression; QuickFixAction.registerQuickFixAction( highlightInfo, new ChangeNewOperatorTypeFix(newType, newExpression)); }
@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; }
@Override public PsiType visitClassType(PsiClassType classType) { final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); final PsiClass aClass = resolveResult.getElement(); if (aClass == null) return classType; PsiUtilCore.ensureValid(aClass); if (aClass instanceof PsiTypeParameter) { final PsiTypeParameter typeParameter = (PsiTypeParameter) aClass; if (containsInMap(typeParameter)) { PsiType result = substituteTypeParameter(typeParameter); if (result != null) { PsiUtil.ensureValidType(result); } return result; } return classType; } final Map<PsiTypeParameter, PsiType> hashMap = new HashMap<PsiTypeParameter, PsiType>(2); if (!processClass(aClass, resolveResult.getSubstitutor(), hashMap)) { return null; } PsiClassType result = JavaPsiFacade.getElementFactory(aClass.getProject()) .createType(aClass, createSubstitutor(hashMap), classType.getLanguageLevel()); PsiUtil.ensureValidType(result); return result; }
@Override public PsiType visitClassType(final PsiClassType classType) { PsiClassType alreadyComputed = myResultMap.get(classType); if (alreadyComputed != null) { return alreadyComputed; } final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics(); final PsiClass psiClass = classResolveResult.getElement(); final PsiSubstitutor substitutor = classResolveResult.getSubstitutor(); if (psiClass == null) return classType; PsiUtilCore.ensureValid(psiClass); final PsiClass mappedClass = mapClass(psiClass); if (mappedClass == null) return classType; PsiClassType mappedType = new PsiCorrectedClassType( classType.getLanguageLevel(), classType, new CorrectedResolveResult(psiClass, mappedClass, substitutor, classResolveResult)); myResultMap.put(classType, mappedType); return mappedType; }
@Nullable private static Boolean isAssignableForNativeTypes( @NotNull PsiType lType, @NotNull PsiClassType rType, @NotNull PsiElement context) { if (!(lType instanceof PsiClassType)) return null; final PsiClassType.ClassResolveResult leftResult = ((PsiClassType) lType).resolveGenerics(); final PsiClassType.ClassResolveResult rightResult = rType.resolveGenerics(); final PsiClass leftClass = leftResult.getElement(); PsiClass rightClass = rightResult.getElement(); if (rightClass == null || leftClass == null) return null; if (!InheritanceUtil.isInheritorOrSelf(rightClass, leftClass, true)) return Boolean.FALSE; PsiSubstitutor rightSubstitutor = rightResult.getSubstitutor(); if (!leftClass.hasTypeParameters()) return Boolean.TRUE; PsiSubstitutor leftSubstitutor = leftResult.getSubstitutor(); if (!leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) { rightSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(leftClass, rightClass, rightSubstitutor); rightClass = leftClass; } else if (!rightClass.hasTypeParameters()) return Boolean.TRUE; Iterator<PsiTypeParameter> li = PsiUtil.typeParametersIterator(leftClass); Iterator<PsiTypeParameter> ri = PsiUtil.typeParametersIterator(rightClass); while (li.hasNext()) { if (!ri.hasNext()) return Boolean.FALSE; PsiTypeParameter lp = li.next(); PsiTypeParameter rp = ri.next(); final PsiType typeLeft = leftSubstitutor.substitute(lp); if (typeLeft == null) continue; final PsiType typeRight = rightSubstitutor.substituteWithBoundsPromotion(rp); if (typeRight == null) { return Boolean.TRUE; } if (!isAssignableWithoutConversions(typeLeft, typeRight, context)) return Boolean.FALSE; } return Boolean.TRUE; }
public PsiType substitute(final PsiType t) { if (t instanceof PsiWildcardType) { final PsiWildcardType wcType = (PsiWildcardType) t; final PsiType bound = wcType.getBound(); if (bound == null) { return t; } final PsiManager manager = PsiManager.getInstance(myProject); final PsiType subst = substitute(bound); if (subst == null) return null; return subst instanceof PsiWildcardType ? subst : wcType.isExtends() ? PsiWildcardType.createExtends(manager, subst) : PsiWildcardType.createSuper(manager, subst); } else if (t instanceof PsiTypeVariable) { final PsiType b = apply(t); if (b instanceof Bottom || b instanceof PsiTypeVariable) { return null; } return substitute(b); } else if (t instanceof Bottom) { return null; } else if (t instanceof PsiArrayType) { return substitute(((PsiArrayType) t).getComponentType()).createArrayType(); } else if (t instanceof PsiClassType) { final PsiClassType.ClassResolveResult result = ((PsiClassType) t).resolveGenerics(); final PsiClass aClass = result.getElement(); final PsiSubstitutor aSubst = result.getSubstitutor(); if (aClass != null) { PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; for (final PsiTypeParameter parm : aSubst.getSubstitutionMap().keySet()) { final PsiType type = aSubst.substitute(parm); theSubst = theSubst.put(parm, substitute(type)); } return JavaPsiFacade.getInstance(aClass.getProject()) .getElementFactory() .createType(aClass, theSubst); } } return t; }
@NotNull @Override public PsiJavaCodeReferenceElement createReferenceElementByType( @NotNull final PsiClassType type) { if (type instanceof PsiClassReferenceType) { return ((PsiClassReferenceType) type).getReference(); } final PsiClassType.ClassResolveResult resolveResult = type.resolveGenerics(); final PsiClass refClass = resolveResult.getElement(); assert refClass != null : type; return new LightClassReference( myManager, type.getCanonicalText(), refClass, resolveResult.getSubstitutor()); }
@Override public Result calculateResult(@NotNull Expression[] params, ExpressionContext context) { if (params.length != 1) return null; final Result result = params[0].calculateResult(context); if (result == null) return null; Project project = context.getProject(); PsiExpression expr = MacroUtil.resultToPsiExpression(result, context); if (expr == null) return null; PsiType type = expr.getType(); if (type instanceof PsiArrayType) { return new PsiTypeResult(((PsiArrayType) type).getComponentType(), project); } if (type instanceof PsiClassType) { PsiClassType.ClassResolveResult resolveResult = ((PsiClassType) type).resolveGenerics(); PsiClass aClass = resolveResult.getElement(); if (aClass != null) { PsiClass iterableClass = JavaPsiFacade.getInstance(project) .findClass("java.lang.Iterable", aClass.getResolveScope()); if (iterableClass != null) { PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor( iterableClass, aClass, resolveResult.getSubstitutor()); if (substitutor != null) { PsiType parameterType = substitutor.substitute(iterableClass.getTypeParameters()[0]); if (parameterType instanceof PsiCapturedWildcardType) { parameterType = ((PsiCapturedWildcardType) parameterType).getWildcard(); } if (parameterType != null) { if (parameterType instanceof PsiWildcardType) { if (((PsiWildcardType) parameterType).isExtends()) { return new PsiTypeResult(((PsiWildcardType) parameterType).getBound(), project); } else return null; } return new PsiTypeResult(parameterType, project); } } } } } return null; }
// uses hierarchy signature tree if available, traverses class structure by itself otherwise public static boolean processDirectSuperMethodsSmart( @NotNull PsiMethod method, @NotNull Processor<PsiMethod> superMethodProcessor) { // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod); PsiClass aClass = method.getContainingClass(); if (aClass == null) return false; if (!canHaveSuperMethod(method, true, false)) return false; Map<MethodSignature, HierarchicalMethodSignature> cachedMap = SIGNATURES_KEY.getCachedValueOrNull(aClass); if (cachedMap != null) { HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); if (signature != null) { List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures(); for (HierarchicalMethodSignature superSignature : superSignatures) { if (!superMethodProcessor.process(superSignature.getMethod())) return false; } return true; } } PsiClassType[] directSupers = aClass.getSuperTypes(); for (PsiClassType directSuper : directSupers) { PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { // generics break; } PsiClass directSuperClass = resolveResult.getElement(); if (directSuperClass == null) continue; PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); for (PsiMethod candidate : candidates) { if (PsiUtil.canBeOverriden(candidate)) { if (!superMethodProcessor.process(candidate)) return false; } } return true; } List<HierarchicalMethodSignature> superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); for (HierarchicalMethodSignature superSignature : superSignatures) { if (!superMethodProcessor.process(superSignature.getMethod())) return false; } return true; }
@Nullable public <T extends PsiType> T correctType(@NotNull T type) { if (type instanceof PsiClassType) { PsiClassType classType = (PsiClassType) type; if (classType.getParameterCount() == 0) { final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics(); final PsiClass psiClass = classResolveResult.getElement(); if (psiClass != null && classResolveResult.getSubstitutor() == PsiSubstitutor.EMPTY) { final PsiClass mappedClass = mapClass(psiClass); if (mappedClass == null || mappedClass == psiClass) return (T) classType; } } } return (T) type.accept(this); }
public PsiType apply(final PsiType type) { if (type instanceof PsiTypeVariable) { final PsiType t = myBindings.get(((PsiTypeVariable) type).getIndex()); return t == null ? type : t; } else if (type instanceof PsiArrayType) { return apply(((PsiArrayType) type).getComponentType()).createArrayType(); } else if (type instanceof PsiClassType) { final PsiClassType.ClassResolveResult result = Util.resolveType(type); final PsiClass theClass = result.getElement(); final PsiSubstitutor aSubst = result.getSubstitutor(); PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; if (theClass != null) { for (final PsiTypeParameter aParm : aSubst.getSubstitutionMap().keySet()) { final PsiType aType = aSubst.substitute(aParm); theSubst = theSubst.put(aParm, apply(aType)); } return JavaPsiFacade.getInstance(theClass.getProject()) .getElementFactory() .createType(theClass, theSubst); } else { return type; } } else if (type instanceof PsiWildcardType) { final PsiWildcardType wcType = (PsiWildcardType) type; final PsiType bound = wcType.getBound(); if (bound != null) { final PsiType abound = apply(bound); if (abound instanceof PsiWildcardType) { return null; } return wcType.isExtends() ? PsiWildcardType.createExtends(PsiManager.getInstance(myProject), abound) : PsiWildcardType.createSuper(PsiManager.getInstance(myProject), abound); } return type; } else { return type; } }
private static void processClassInner( PsiClassType type, PsiSubstitutor superClassSubstitutor, boolean shouldProcessDeprecated, List<PsiMethod> result, GrTypeDefinition classToDelegateTo, Set<PsiClass> processedWithoutDeprecated, Set<PsiClass> processedAll, boolean keepParameterAnnotationsNew) { final PsiClassType.ClassResolveResult resolveResult = type.resolveGenerics(); final PsiClass psiClass = resolveResult.getElement(); if (psiClass == null) return; final String qname = psiClass.getQualifiedName(); if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname)) return; if (GroovyCommonClassNames.GROOVY_OBJECT.equals(qname)) return; if (GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT.equals(qname)) return; final PsiSubstitutor substitutor = TypesUtil.composeSubstitutors(resolveResult.getSubstitutor(), superClassSubstitutor); if (processedAll.contains(psiClass)) return; if (!shouldProcessDeprecated && processedWithoutDeprecated.contains(psiClass)) return; if (shouldProcessDeprecated) { processedAll.add(psiClass); } else { processedWithoutDeprecated.add(psiClass); } collectMethods( psiClass, substitutor, shouldProcessDeprecated, classToDelegateTo, result, keepParameterAnnotationsNew); process( psiClass, substitutor, shouldProcessDeprecated, processedWithoutDeprecated, processedAll, result, classToDelegateTo, keepParameterAnnotationsNew); }
private Pair<PsiVariable, PsiType> findVariable(final PsiElement element) { PsiVariable variable = null; if (element instanceof PsiIdentifier) { if (element.getParent() instanceof PsiVariable) { variable = (PsiVariable) element.getParent(); } } else if (element instanceof PsiJavaToken) { final PsiJavaToken token = (PsiJavaToken) element; if (token.getTokenType() != JavaTokenType.EQ) return null; if (token.getParent() instanceof PsiVariable) { variable = (PsiVariable) token.getParent(); } } if (variable == null) { return null; } variableName = variable.getName(); final PsiExpression initializer = variable.getInitializer(); if (initializer == null) return null; final PsiType variableType = variable.getType(); final PsiType initializerType = initializer.getType(); if (!(variableType instanceof PsiClassType)) return null; final PsiClassType variableClassType = (PsiClassType) variableType; if (!variableClassType.isRaw()) return null; if (!(initializerType instanceof PsiClassType)) return null; final PsiClassType initializerClassType = (PsiClassType) initializerType; if (initializerClassType.isRaw()) return null; final PsiClassType.ClassResolveResult variableResolveResult = variableClassType.resolveGenerics(); final PsiClassType.ClassResolveResult initializerResolveResult = initializerClassType.resolveGenerics(); if (initializerResolveResult.getElement() == null) return null; final PsiSubstitutor targetSubstitutor = TypeConversionUtil.getClassSubstitutor( variableResolveResult.getElement(), initializerResolveResult.getElement(), initializerResolveResult.getSubstitutor()); if (targetSubstitutor == null) return null; PsiType type = JavaPsiFacade.getInstance(variable.getProject()) .getElementFactory() .createType(variableResolveResult.getElement(), targetSubstitutor); newTypeName = type.getCanonicalText(); return Pair.create(variable, type); }
@Nullable public static PsiType getSubstitutedType(@Nullable PsiParameter parameter) { if (parameter == null) return null; final PsiType type = getType(parameter); if (type instanceof PsiArrayType) { return type; } final PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type); final PsiClass psiClass = result.getElement(); if (psiClass == null) return type; final Set<PsiTypeParameter> usedTypeParameters = new HashSet<PsiTypeParameter>(); RefactoringUtil.collectTypeParameters(usedTypeParameters, parameter); for (Iterator<PsiTypeParameter> iterator = usedTypeParameters.iterator(); iterator.hasNext(); ) { PsiTypeParameter usedTypeParameter = iterator.next(); if (parameter.getDeclarationScope() != usedTypeParameter.getOwner()) { iterator.remove(); } } PsiSubstitutor subst = PsiSubstitutor.EMPTY; for (PsiTypeParameter usedTypeParameter : usedTypeParameters) { subst = subst.put(usedTypeParameter, TypeConversionUtil.typeParameterErasure(usedTypeParameter)); } PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; final Map<PsiTypeParameter, PsiType> typeMap = result.getSubstitutor().getSubstitutionMap(); for (PsiTypeParameter typeParameter : typeMap.keySet()) { final PsiType psiType = typeMap.get(typeParameter); substitutor = substitutor.put(typeParameter, psiType != null ? subst.substitute(psiType) : null); } if (psiClass instanceof PsiTypeParameter) { return subst.substitute((PsiTypeParameter) psiClass); } else { return JavaPsiFacade.getElementFactory(parameter.getProject()) .createType(psiClass, substitutor); } }
@Nullable private static PsiType getCollectionComponentType(PsiType type, Project project) { if (!(type instanceof PsiClassType)) return null; PsiClassType classType = (PsiClassType) type; PsiClassType.ClassResolveResult result = classType.resolveGenerics(); PsiClass clazz = result.getElement(); if (clazz == null) return null; JavaPsiFacade facade = JavaPsiFacade.getInstance(project); @SuppressWarnings({"ConstantConditions"}) PsiClass collectionClass = facade.findClass("java.util.Collection", type.getResolveScope()); if (collectionClass == null || collectionClass.getTypeParameters().length != 1) return null; PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(collectionClass, clazz, result.getSubstitutor()); if (substitutor == null) return null; PsiType componentType = substitutor.substitute(collectionClass.getTypeParameters()[0]); return componentType instanceof PsiIntersectionType ? null : componentType; }
private static PsiTypeLookupItem doCreateItem( final PsiType type, PsiElement context, int bracketsCount, boolean diamond, InsertHandler<PsiTypeLookupItem> importFixer) { if (type instanceof PsiClassType) { PsiClassType.ClassResolveResult classResolveResult = ((PsiClassType) type).resolveGenerics(); final PsiClass psiClass = classResolveResult.getElement(); if (psiClass != null) { String name = psiClass.getName(); if (name != null) { final PsiSubstitutor substitutor = classResolveResult.getSubstitutor(); PsiClass resolved = JavaPsiFacade.getInstance(psiClass.getProject()) .getResolveHelper() .resolveReferencedClass(name, context); Set<String> allStrings = new HashSet<String>(); allStrings.add(name); if (!psiClass.getManager().areElementsEquivalent(resolved, psiClass) && !PsiUtil.isInnerClass(psiClass)) { // inner class name should be shown qualified if its not accessible by single name PsiClass aClass = psiClass.getContainingClass(); while (aClass != null && !PsiUtil.isInnerClass(aClass) && aClass.getName() != null) { name = aClass.getName() + '.' + name; allStrings.add(name); aClass = aClass.getContainingClass(); } } PsiTypeLookupItem item = new PsiTypeLookupItem( psiClass, name, diamond, bracketsCount, importFixer, substitutor); item.addLookupStrings(ArrayUtil.toStringArray(allStrings)); return item; } } } return new PsiTypeLookupItem( type, type.getPresentableText(), false, bracketsCount, importFixer, PsiSubstitutor.EMPTY); }
private static boolean processSuperTypes( @NotNull PsiClass aClass, @NotNull PsiScopeProcessor processor, @Nullable Set<PsiClass> visited, PsiElement last, @NotNull PsiElement place, @NotNull ResolveState state, boolean isRaw, @NotNull PsiElementFactory factory, @NotNull LanguageLevel languageLevel) { boolean resolved = false; for (final PsiClassType superType : aClass.getSuperTypes()) { final PsiClassType.ClassResolveResult superTypeResolveResult = superType.resolveGenerics(); PsiClass superClass = superTypeResolveResult.getElement(); if (superClass == null) continue; PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor( superClass, superTypeResolveResult.getSubstitutor(), aClass, state.get(PsiSubstitutor.KEY), factory, languageLevel); if (aClass instanceof PsiTypeParameter && PsiUtil.isRawSubstitutor(superClass, finalSubstitutor)) { finalSubstitutor = PsiSubstitutor.EMPTY; } if (!processDeclarationsInClass( superClass, processor, state.put(PsiSubstitutor.KEY, finalSubstitutor), visited, last, place, isRaw)) { resolved = true; } } return !resolved; }
private boolean hasTypeParametersToInfer(PsiClassType classType) { final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); PsiClass aClass = resolveResult.getElement(); if (aClass == null) return false; final Iterable<PsiTypeParameter> iterable = com.intellij.psi.util.PsiUtil.typeParametersIterable(aClass); if (!iterable.iterator().hasNext()) { return false; } for (PsiTypeParameter parameter : iterable) { PsiType type = resolveResult.getSubstitutor().substitute(parameter); if (type != null) { if (!(type instanceof PsiWildcardType) || ((PsiWildcardType) type).getBound() != null) { return false; } } } return true; }
private static LookupItem doCreateItem(PsiType type, PsiElement context) { if (type instanceof PsiClassType) { PsiClassType.ClassResolveResult classResolveResult = ((PsiClassType) type).resolveGenerics(); final PsiClass psiClass = classResolveResult.getElement(); final PsiSubstitutor substitutor = classResolveResult.getSubstitutor(); final String text = type.getCanonicalText(); String typeString = text; String typeParams = ""; if (text.indexOf('<') > 0 && text.endsWith(">")) { typeString = text.substring(0, text.indexOf('<')); typeParams = text.substring(text.indexOf('<')); } String lookupString = text.substring(typeString.lastIndexOf('.') + 1); if (psiClass != null) { PsiClass resolved = JavaPsiFacade.getInstance(psiClass.getProject()) .getResolveHelper() .resolveReferencedClass(psiClass.getName(), context); if (!psiClass.getManager().areElementsEquivalent(resolved, psiClass)) { // inner class name should be shown qualified if its not accessible by single name PsiClass aClass = psiClass; lookupString = ""; while (aClass != null) { lookupString = aClass.getName() + (lookupString == "" ? "" : ".") + lookupString; aClass = aClass.getContainingClass(); } lookupString += typeParams; } LookupItem item = new PsiTypeLookupItem(psiClass, lookupString); item.setAttribute(SUBSTITUTOR, substitutor); return item; } } return new LookupItem(type, type.getPresentableText()); }
public static void processSubTypes( PsiType psiType, final PsiElement context, boolean getRawSubtypes, @NotNull final PrefixMatcher matcher, Consumer<PsiType> consumer) { int arrayDim = psiType.getArrayDimensions(); psiType = psiType.getDeepComponentType(); if (!(psiType instanceof PsiClassType)) return; final Condition<String> shortNameCondition = new Condition<String>() { @Override public boolean value(String s) { return matcher.prefixMatches(s); } }; final PsiClassType baseType = (PsiClassType) psiType; final PsiClassType.ClassResolveResult baseResult = ApplicationManager.getApplication() .runReadAction( new Computable<PsiClassType.ClassResolveResult>() { @Override public PsiClassType.ClassResolveResult compute() { return JavaCompletionUtil.originalize(baseType).resolveGenerics(); } }); final PsiClass baseClass = baseResult.getElement(); final PsiSubstitutor baseSubstitutor = baseResult.getSubstitutor(); if (baseClass == null) return; final GlobalSearchScope scope = ApplicationManager.getApplication() .runReadAction( new Computable<GlobalSearchScope>() { @Override public GlobalSearchScope compute() { return context.getResolveScope(); } }); final Processor<PsiClass> inheritorsProcessor = createInheritorsProcessor( context, baseType, arrayDim, getRawSubtypes, consumer, baseClass, baseSubstitutor); if (matcher.getPrefix().length() > 2) { AllClassesGetter.processJavaClasses( matcher, context.getProject(), scope, new Processor<PsiClass>() { @Override public boolean process(PsiClass psiClass) { if (psiClass.isInheritor(baseClass, true)) { return inheritorsProcessor.process(psiClass); } return true; } }); } else { final Query<PsiClass> baseQuery = ClassInheritorsSearch.search( new ClassInheritorsSearch.SearchParameters( baseClass, scope, true, false, false, shortNameCondition)); final Query<PsiClass> query = new FilteredQuery<PsiClass>( baseQuery, new Condition<PsiClass>() { @Override public boolean value(final PsiClass psiClass) { return !(psiClass instanceof PsiTypeParameter); } }); query.forEach(inheritorsProcessor); } }
@Nullable public <T extends PsiExpression> PsiType getType( @NotNull T expr, @NotNull Function<T, PsiType> f) { PsiType type = getCachedType(expr); if (type == null) { final RecursionGuard.StackStamp dStackStamp = PsiDiamondType.ourDiamondGuard.markStack(); final RecursionGuard.StackStamp gStackStamp = PsiResolveHelper.ourGraphGuard.markStack(); type = f.fun(expr); if (!dStackStamp.mayCacheNow() || !gStackStamp.mayCacheNow()) { return type; } if (type == null) type = TypeConversionUtil.NULL_TYPE; Reference<PsiType> ref = new SoftReference<PsiType>(type); myCalculatedTypes.put(expr, ref); if (type instanceof PsiClassReferenceType) { // convert reference-based class type to the PsiImmediateClassType, since the reference may // become invalid PsiClassType.ClassResolveResult result = ((PsiClassReferenceType) type).resolveGenerics(); PsiClass psiClass = result.getElement(); type = psiClass == null ? type // for type with unresolved reference, leave it in the cache // for clients still might be able to retrieve its getCanonicalText() from the // reference text : new PsiImmediateClassType( psiClass, result.getSubstitutor(), ((PsiClassReferenceType) type).getLanguageLevel(), type.getAnnotations()); } } if (!type.isValid()) { if (expr.isValid()) { PsiJavaCodeReferenceElement refInside = type instanceof PsiClassReferenceType ? ((PsiClassReferenceType) type).getReference() : null; @NonNls String typeinfo = type + " (" + type.getClass() + ")" + (refInside == null ? "" : "; ref inside: " + refInside + " (" + refInside.getClass() + ") valid:" + refInside.isValid()); LOG.error( "Type is invalid: " + typeinfo + "; expr: '" + expr + "' (" + expr.getClass() + ") is valid"); } else { LOG.error("Expression: '" + expr + "' is invalid, must not be used for getType()"); } } return type == TypeConversionUtil.NULL_TYPE ? null : type; }
private static Map<MethodSignature, HierarchicalMethodSignature> buildMethodHierarchy( PsiClass aClass, PsiSubstitutor substitutor, final boolean includePrivates, final Set<PsiClass> visited, boolean isInRawContext) { Map<MethodSignature, HierarchicalMethodSignature> result = new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>(); final Map<MethodSignature, List<PsiMethod>> sameParameterErasureMethods = new THashMap<MethodSignature, List<PsiMethod>>( MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); Map<MethodSignature, HierarchicalMethodSignatureImpl> map = new THashMap<MethodSignature, HierarchicalMethodSignatureImpl>( new TObjectHashingStrategy<MethodSignature>() { @Override public int computeHashCode(MethodSignature signature) { return MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.computeHashCode( signature); } @Override public boolean equals(MethodSignature o1, MethodSignature o2) { if (!MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.equals(o1, o2)) return false; List<PsiMethod> list = sameParameterErasureMethods.get(o1); boolean toCheckReturnType = list != null && list.size() > 1; if (!toCheckReturnType) return true; PsiType returnType1 = ((MethodSignatureBackedByPsiMethod) o1).getMethod().getReturnType(); PsiType returnType2 = ((MethodSignatureBackedByPsiMethod) o2).getMethod().getReturnType(); if (returnType1 == null && returnType2 == null) return true; if (returnType1 == null || returnType2 == null) return false; PsiType erasure1 = TypeConversionUtil.erasure(o1.getSubstitutor().substitute(returnType1)); PsiType erasure2 = TypeConversionUtil.erasure(o2.getSubstitutor().substitute(returnType2)); return erasure1.equals(erasure2); } }); for (PsiMethod method : aClass.getMethods()) { if (!method.isValid()) { throw new PsiInvalidElementAccessException( method, "class.valid=" + aClass.isValid() + "; name=" + method.getName()); } if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue; final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext); HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature); List<PsiMethod> list = sameParameterErasureMethods.get(signature); if (list == null) { list = new SmartList<PsiMethod>(); sameParameterErasureMethods.put(signature, list); } list.add(method); LOG.assertTrue(newH.getMethod().isValid()); result.put(signature, newH); map.put(signature, newH); } for (PsiClassType superType : aClass.getSuperTypes()) { PsiClassType.ClassResolveResult superTypeResolveResult = superType.resolveGenerics(); PsiClass superClass = superTypeResolveResult.getElement(); if (superClass == null) continue; if (!visited.add(superClass)) continue; // cyclic inheritance final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor(); PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext); final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0; Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper); visited.remove(superClass); List<Pair<MethodSignature, HierarchicalMethodSignature>> flattened = new ArrayList<Pair<MethodSignature, HierarchicalMethodSignature>>(); for (Map.Entry<MethodSignature, HierarchicalMethodSignature> entry : superResult.entrySet()) { HierarchicalMethodSignature hms = entry.getValue(); MethodSignature signature = entry.getKey(); PsiClass containingClass = hms.getMethod().getContainingClass(); List<HierarchicalMethodSignature> supers = new ArrayList<HierarchicalMethodSignature>(hms.getSuperSignatures()); for (HierarchicalMethodSignature aSuper : supers) { PsiClass superContainingClass = aSuper.getMethod().getContainingClass(); if (containingClass != null && superContainingClass != null && !containingClass.isInheritor(superContainingClass, true)) { // methods must be inherited from unrelated classes, so flatten hierarchy here // class C implements SAM1, SAM2 { void methodimpl() {} } // hms.getSuperSignatures().remove(aSuper); flattened.add( new Pair<MethodSignature, HierarchicalMethodSignature>(signature, aSuper)); } } putInMap(aClass, result, map, hms, signature); } for (Pair<MethodSignature, HierarchicalMethodSignature> pair : flattened) { putInMap(aClass, result, map, pair.second, pair.first); } } for (Map.Entry<MethodSignature, HierarchicalMethodSignatureImpl> entry : map.entrySet()) { HierarchicalMethodSignatureImpl hierarchicalMethodSignature = entry.getValue(); MethodSignature methodSignature = entry.getKey(); if (result.get(methodSignature) == null && PsiUtil.isAccessible( aClass.getProject(), hierarchicalMethodSignature.getMethod(), aClass, aClass)) { LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid()); result.put(methodSignature, hierarchicalMethodSignature); } } return result; }
// uses hierarchy signature tree if available, traverses class structure by itself otherwise public static boolean isSuperMethodSmart( @NotNull PsiMethod method, @NotNull PsiMethod superMethod) { // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod); if (method == superMethod) return false; PsiClass aClass = method.getContainingClass(); PsiClass superClass = superMethod.getContainingClass(); if (aClass == null || superClass == null || superClass == aClass) return false; if (!canHaveSuperMethod(method, true, false)) return false; PsiMethod[] superMethods = null; Map<MethodSignature, HierarchicalMethodSignature> cachedMap = SIGNATURES_KEY.getCachedValueOrNull(aClass); if (cachedMap != null) { HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); if (signature != null) { superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures()); } } if (superMethods == null) { PsiClassType[] directSupers = aClass.getSuperTypes(); List<PsiMethod> found = null; boolean canceled = false; for (PsiClassType directSuper : directSupers) { PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { // generics canceled = true; break; } PsiClass directSuperClass = resolveResult.getElement(); if (directSuperClass == null) continue; PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); if (candidates.length != 0) { if (found == null) found = new ArrayList<PsiMethod>(); for (PsiMethod candidate : candidates) { if (PsiUtil.canBeOverriden(candidate)) found.add(candidate); } } } superMethods = canceled ? null : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]); } if (superMethods == null) { superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods( method.getHierarchicalMethodSignature().getSuperSignatures()); } for (PsiMethod superCandidate : superMethods) { if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod)) return true; } return false; }
@NotNull private static LookupElement castQualifier( @NotNull LookupElement item, @Nullable final PsiTypeLookupItem castTypeItem, @Nullable PsiType plainQualifier, JavaCompletionProcessor processor) { if (castTypeItem == null) { return item; } if (plainQualifier != null) { Object o = item.getObject(); if (o instanceof PsiMethod) { PsiType castType = castTypeItem.getType(); if (plainQualifier instanceof PsiClassType && castType instanceof PsiClassType) { PsiMethod method = (PsiMethod) o; PsiClassType.ClassResolveResult plainResult = ((PsiClassType) plainQualifier).resolveGenerics(); PsiClass plainClass = plainResult.getElement(); if (plainClass != null && plainClass.findMethodBySignature(method, true) != null) { PsiClass castClass = ((PsiClassType) castType).resolveGenerics().getElement(); if (castClass == null || !castClass.isInheritor(plainClass, true)) { return item; } PsiSubstitutor plainSub = plainResult.getSubstitutor(); PsiSubstitutor castSub = TypeConversionUtil.getSuperClassSubstitutor(plainClass, (PsiClassType) castType); PsiType returnType = method.getReturnType(); if (method.getSignature(plainSub).equals(method.getSignature(castSub))) { PsiType typeAfterCast = toRaw(castSub.substitute(returnType)); PsiType typeDeclared = toRaw(plainSub.substitute(returnType)); if (typeAfterCast != null && typeDeclared != null && typeAfterCast.isAssignableFrom(typeDeclared) && processor.isAccessible(plainClass.findMethodBySignature(method, true))) { return item; } } } } } else if (containsMember(plainQualifier, o)) { return item; } } return LookupElementDecorator.withInsertHandler( item, new InsertHandlerDecorator<LookupElement>() { @Override public void handleInsert( InsertionContext context, LookupElementDecorator<LookupElement> item) { final Document document = context.getEditor().getDocument(); context.commitDocument(); final PsiFile file = context.getFile(); final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset( file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null) { final PsiElement qualifier = ref.getQualifier(); if (qualifier != null) { final CommonCodeStyleSettings settings = context.getCodeStyleSettings(); final String parenSpace = settings.SPACE_WITHIN_PARENTHESES ? " " : ""; document.insertString(qualifier.getTextRange().getEndOffset(), parenSpace + ")"); final String spaceWithin = settings.SPACE_WITHIN_CAST_PARENTHESES ? " " : ""; final String prefix = "(" + parenSpace + "(" + spaceWithin; final String spaceAfter = settings.SPACE_AFTER_TYPE_CAST ? " " : ""; final int exprStart = qualifier.getTextRange().getStartOffset(); document.insertString(exprStart, prefix + spaceWithin + ")" + spaceAfter); CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), castTypeItem); PsiDocumentManager.getInstance(file.getProject()) .doPostponedOperationsAndUnblockDocument(document); context.getEditor().getCaretModel().moveToOffset(context.getTailOffset()); } } item.getDelegate().handleInsert(context); } }); }
private static boolean provablyDistinct(PsiType type1, PsiType type2, int level) { if (type1 instanceof PsiClassType && ((PsiClassType) type1).resolve() instanceof PsiTypeParameter) return false; if (type2 instanceof PsiClassType && ((PsiClassType) type2).resolve() instanceof PsiTypeParameter) return false; if (type1 instanceof PsiWildcardType) { if (type2 instanceof PsiWildcardType) { return provablyDistinct((PsiWildcardType) type1, (PsiWildcardType) type2); } if (type2 instanceof PsiCapturedWildcardType) { return ((PsiWildcardType) type1).isExtends() && level > 0 || provablyDistinct( (PsiWildcardType) type1, ((PsiCapturedWildcardType) type2).getWildcard()); } if (type2 instanceof PsiClassType) { final PsiClass psiClass2 = PsiUtil.resolveClassInType(type2); if (psiClass2 == null) return false; if (((PsiWildcardType) type1).isExtends()) { final PsiType extendsBound = ((PsiWildcardType) type1).getExtendsBound(); if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) extendsBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound); if (boundClass1 == null) return false; return proveExtendsBoundsDistinct(type1, type2, boundClass1, psiClass2); } if (((PsiWildcardType) type1).isSuper()) { final PsiType superBound = ((PsiWildcardType) type1).getSuperBound(); if (superBound instanceof PsiArrayType && proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) superBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound); if (boundClass1 == null || boundClass1 instanceof PsiTypeParameter) return false; return !InheritanceUtil.isInheritorOrSelf(boundClass1, psiClass2, true); } final PsiType bound = ((PsiWildcardType) type1).getBound(); return bound != null && !bound.equals(psiClass2); } if (type2 instanceof PsiArrayType) { return proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) type2, type1); } } if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType) type1).getWildcard(), type2, level); if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1, level); final PsiClassType.ClassResolveResult classResolveResult1 = PsiUtil.resolveGenericsClassInType(type1); final PsiClassType.ClassResolveResult classResolveResult2 = PsiUtil.resolveGenericsClassInType(type2); if (Comparing.equal(TypeConversionUtil.erasure(type1), TypeConversionUtil.erasure(type2))) { final PsiSubstitutor substitutor1 = classResolveResult1.getSubstitutor(); final PsiSubstitutor substitutor2 = classResolveResult2.getSubstitutor(); for (PsiTypeParameter parameter : substitutor1.getSubstitutionMap().keySet()) { final PsiType substitutedType1 = substitutor1.substitute(parameter); final PsiType substitutedType2 = substitutor2.substitute(parameter); if (substitutedType1 == null && substitutedType2 == null) return false; if (substitutedType1 == null || substitutedType2 == null) { return true; } else { if (provablyDistinct(substitutedType1, substitutedType2, level + 1)) return true; if (substitutedType1 instanceof PsiWildcardType && !((PsiWildcardType) substitutedType1).isBounded()) return true; } } return false; } final PsiClass boundClass1 = classResolveResult1.getElement(); final PsiClass boundClass2 = classResolveResult2.getElement(); return type2 != null && type1 != null && !type1.equals(type2) && (!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true) || !InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true)); }