@Override public Stream<LookupElementBuilder> resolveCompletions(String propertyName, PsiType psiType) { PsiType[] parameters = ((PsiClassReferenceType) psiType).getParameters(); Stream<PsiClass> psiClassStream = null; if (parameters.length == 1 && parameters[0] instanceof PsiWildcardType) { PsiWildcardType psiWildcardType = ((PsiWildcardType) parameters[0]); if (psiWildcardType.isBounded()) { if (psiWildcardType.isExtends()) { psiClassStream = subClasses((PsiClassType) psiWildcardType.getExtendsBound()).stream(); } else if (psiWildcardType.isSuper()) { psiClassStream = superClasses((PsiClassType) psiWildcardType.getSuperBound()).stream(); } } } if (psiClassStream != null) { return psiClassStream.map(this::buildClassLookup).filter(Optional::isPresent).map(Optional::get); } else { return Stream.empty(); } }
private static PsiType maybeGetLowerBound( PsiWildcardType type, TypeVarToTypeMap actualParamByVarName, boolean bKeepTypeVars, LinkedHashSet<PsiType> recursiveTypes ) { PsiType lower = type.getSuperBound(); if( lower != PsiType.NULL && recursiveTypes.size() > 0 ) { // This is a "super" (contravariant) wildcard LinkedList<PsiType> list = new LinkedList<>( recursiveTypes ); PsiType enclType = list.getLast(); if( isParameterizedType( enclType ) ) { PsiType genType = getActualType( ((PsiClassType)enclType).rawType(), actualParamByVarName, bKeepTypeVars, recursiveTypes ); if( LambdaUtil.isFunctionalType( genType ) ) { // For functional interfaces we keep the lower bound as an upper bound so that blocks maintain contravariance wrt the single method's parameters return lower; } } } return null; }
@Nullable private static PsiType[] guessTypes(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[] types = GuessManager.getInstance(project).guessContainerElementType(expr, new TextRange(context.getTemplateStartOffset(), context.getTemplateEndOffset())); for (int i = 0; i < types.length; i++) { PsiType type = types[i]; if (type instanceof PsiWildcardType) { if (((PsiWildcardType)type).isExtends()) { types[i] = ((PsiWildcardType)type).getBound(); } else { types[i] = PsiType.getJavaLangObject(expr.getManager(), expr.getResolveScope()); } } } return types; }
@Nullable @Override protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { PsiFile file = closure.getContainingFile(); if (file == null || !FileUtilRt.extensionEquals(file.getName(), GradleConstants.EXTENSION)) return null; PsiType psiType = super.getClosureParameterType(closure, index); if (psiType instanceof PsiWildcardType) { PsiWildcardType wildcardType = (PsiWildcardType)psiType; if (wildcardType.isSuper() && wildcardType.getBound() != null && wildcardType.getBound().equalsToText(GradleCommonClassNames.GRADLE_API_SOURCE_SET)) { return wildcardType.getBound(); } if (wildcardType.isSuper() && wildcardType.getBound() != null && wildcardType.getBound().equalsToText(GradleCommonClassNames.GRADLE_API_DISTRIBUTION)) { return wildcardType.getBound(); } } return null; }
public String getName() { PsiType type = psiType; if (type instanceof PsiWildcardType) { type = ((PsiWildcardType)type).getBound(); } if (type instanceof PsiClassType) { final PsiClass resolve = ((PsiClassType)type).resolve(); if (resolve != null) { return resolve.getName(); } final String canonicalText = type.getCanonicalText(); final int i = canonicalText.indexOf('<'); if (i < 0) return canonicalText; return canonicalText.substring(0, i); } if (type == null) { return ""; } return type.getCanonicalText(); }
@NotNull public static PsiType extractAllElementType(@NotNull PsiType psiType, @NotNull PsiManager psiManager, final String superClass, final int paramIndex) { PsiType oneElementType = PsiUtil.substituteTypeParameter(psiType, superClass, paramIndex, true); if (oneElementType instanceof PsiWildcardType) { oneElementType = ((PsiWildcardType) oneElementType).getBound(); } PsiType result; final PsiClassType javaLangObject = PsiType.getJavaLangObject(psiManager, GlobalSearchScope.allScope(psiManager.getProject())); if (null == oneElementType || Comparing.equal(javaLangObject, oneElementType)) { result = PsiWildcardType.createUnbounded(psiManager); } else { result = PsiWildcardType.createExtends(psiManager, oneElementType); } return result; }
/** * a = S & a <: T imply S <: T * or * a = S & T <: a imply T <: S * or * S <: a & a <: T imply S <: T */ private void upDown(Collection<PsiType> eqBounds, Collection<PsiType> upperBounds) { for(PsiType upperBound : upperBounds) { if(upperBound == null || PsiType.NULL.equals(upperBound) || upperBound instanceof PsiWildcardType) { continue; } for(PsiType eqBound : eqBounds) { if(eqBound == null || PsiType.NULL.equals(eqBound) || eqBound instanceof PsiWildcardType) { continue; } if(JAVAC_UNCHECKED_SUBTYPING_DURING_INCORPORATION && TypeCompatibilityConstraint.isUncheckedConversion(upperBound, eqBound)) { continue; } addConstraint(new StrictSubtypingConstraint(upperBound, eqBound)); } } }
/** * If two bounds have the form α <: S and α <: T, and if for some generic class or interface, G, * there exists a supertype (4.10) of S of the form G<S1, ..., Sn> and a supertype of T of the form G<T1, ..., Tn>, * then for all i, 1 ≤ i ≤ n, if Si and Ti are types (not wildcards), the constraint ⟨Si = Ti⟩ is implied. */ private boolean upUp(List<PsiType> upperBounds) { return InferenceSession.findParameterizationOfTheSameGenericClass(upperBounds, new Processor<Pair<PsiType, PsiType>>() { @Override public boolean process(Pair<PsiType, PsiType> pair) { final PsiType sType = pair.first; final PsiType tType = pair.second; if(!(sType instanceof PsiWildcardType) && !(tType instanceof PsiWildcardType) && sType != null && tType != null) { addConstraint(new TypeEqualityConstraint(sType, tType)); } return false; } }) != null; }
@Override public PsiType adjustInferredType(PsiManager manager, PsiType guess, ConstraintType constraintType) { if(guess != null && !(guess instanceof PsiWildcardType)) { if(constraintType == ConstraintType.SUPERTYPE) { return PsiWildcardType.createExtends(manager, guess); } else if(constraintType == ConstraintType.SUBTYPE) { return PsiWildcardType.createSuper(manager, guess); } } return guess; }
@Override @NotNull public PsiType getType() { final GrTypeElement boundTypeElement = getBoundTypeElement(); if (boundTypeElement == null) return PsiWildcardType.createUnbounded(getManager()); if (isExtends()) return PsiWildcardType.createExtends(getManager(), boundTypeElement.getType()); if (isSuper()) return PsiWildcardType.createSuper(getManager(), boundTypeElement.getType()); LOG.error("Untested case"); return null; }
@Nullable @Override public Object visitWildcardType(PsiWildcardType wildcardType) { if (wildcardType.getBound() != null) { wildcardType.getBound().accept(this); } typeParameterBuilder.withSubTypes(wildcardType.isExtends()); typeParameterBuilder.withSuperTypes(wildcardType.isSuper()); return super.visitWildcardType(wildcardType); }
@NotNull public PsiType getType() { final GrTypeElement boundTypeElement = getBoundTypeElement(); if (boundTypeElement == null) return PsiWildcardType.createUnbounded(getManager()); if (isExtends()) return PsiWildcardType.createExtends(getManager(), boundTypeElement.getType()); if (isSuper()) return PsiWildcardType.createSuper(getManager(), boundTypeElement.getType()); LOG.error("Untested case"); return null; }
@NotNull public static PsiType extractOneElementType(@NotNull PsiType psiType, @NotNull PsiManager psiManager, final String superClass, final int paramIndex) { PsiType oneElementType = PsiUtil.substituteTypeParameter(psiType, superClass, paramIndex, true); if (oneElementType instanceof PsiWildcardType) { oneElementType = ((PsiWildcardType) oneElementType).getBound(); } if (null == oneElementType) { oneElementType = PsiType.getJavaLangObject(psiManager, GlobalSearchScope.allScope(psiManager.getProject())); } return oneElementType; }
@Nullable private PsiType patchGetClass(@Nullable PsiType type) { if(myMember instanceof PsiMethod && PsiTypesUtil.isGetClass((PsiMethod) myMember) && type instanceof PsiClassType) { PsiType arg = ContainerUtil.getFirstItem(Arrays.asList(((PsiClassType) type).getParameters())); PsiType bound = arg instanceof PsiWildcardType ? TypeConversionUtil.erasure(((PsiWildcardType) arg).getExtendsBound()) : null; if(bound != null) { return PsiTypesUtil.createJavaLangClassType(myMember, bound, false); } } return type; }
@Override public Pair<PsiType, ConstraintType> getInferredTypeWithNoConstraint(PsiManager psiManager, PsiType superType) { if(!(superType instanceof PsiWildcardType)) { return new Pair<>(PsiWildcardType.createExtends(psiManager, superType), ConstraintType.EQUALS); } else { return Pair.create(superType, ConstraintType.SUBTYPE); } }
public static PsiType replaceTypeVariableTypeParametersWithBoundingTypes( PsiType type, PsiType enclType ) { if( isTypeVariable( type ) ) { PsiClass boundingType = getBoundingType( (PsiTypeParameter)((PsiClassType)type).resolve() ); if( isRecursiveType( (PsiClassType)type, type( boundingType ) ) ) { // short-circuit recursive typevar return ((PsiClassType)type( boundingType )).rawType(); } if( enclType != null && isParameterizedType( enclType ) ) { TypeVarToTypeMap map = mapTypeByVarName( enclType, enclType ); return replaceTypeVariableTypeParametersWithBoundingTypes( getActualType( type( boundingType ), map, true ) ); } return replaceTypeVariableTypeParametersWithBoundingTypes( type( boundingType ), enclType ); } if( type.getArrayDimensions() > 0 ) { return new PsiArrayType( replaceTypeVariableTypeParametersWithBoundingTypes( ((PsiArrayType)type).getComponentType(), enclType ) ); } if( type instanceof PsiIntersectionType ) { PsiType[] types = ((PsiIntersectionType)type).getConjuncts(); Set<PsiType> newTypes = new HashSet<>(); for( PsiType t : types ) { newTypes.add( replaceTypeVariableTypeParametersWithBoundingTypes( t ) ); } if( newTypes.size() == 1 ) { return newTypes.iterator().next(); } return PsiIntersectionType.createIntersection( new ArrayList<>( newTypes ) ); } if( isParameterizedType( type ) ) { PsiType[] typeParams = ((PsiClassType)type).getParameters(); PsiType[] concreteParams = new PsiType[typeParams.length]; for( int i = 0; i < typeParams.length; i++ ) { concreteParams[i] = replaceTypeVariableTypeParametersWithBoundingTypes( typeParams[i], enclType ); } type = parameterizeType( (PsiClassType)type, concreteParams ); } else if( type instanceof PsiClassType ) { PsiClass psiClass = ((PsiClassType)type).resolve(); PsiTypeParameter[] typeVars = psiClass.getTypeParameters(); PsiType[] boundingTypes = new PsiType[typeVars.length]; for( int i = 0; i < boundingTypes.length; i++ ) { boundingTypes[i] = type( getBoundingType( typeVars[i] ) ); if( isRecursiveType( (PsiClassType)type( typeVars[i] ), boundingTypes[i] ) ) { return type; } } for( int i = 0; i < boundingTypes.length; i++ ) { boundingTypes[i] = replaceTypeVariableTypeParametersWithBoundingTypes( boundingTypes[i], enclType ); } type = parameterizeType( (PsiClassType)type, boundingTypes ); } else if( type instanceof PsiWildcardType ) { replaceTypeVariableTypeParametersWithBoundingTypes( ((PsiWildcardType)type).getExtendsBound() ); } return type; }
@Nullable @Override protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { List<PsiType> expectedTypes; if (closure.getParent() instanceof GrSafeCastExpression) { GrSafeCastExpression safeCastExpression = (GrSafeCastExpression)closure.getParent(); GrTypeElement typeElement = safeCastExpression.getCastTypeElement(); if (typeElement != null) { PsiType castType = typeElement.getType(); expectedTypes = ContainerUtil.newArrayList(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); for (Iterator<PsiType> iterator = expectedTypes.iterator(); iterator.hasNext(); ) { if (!TypesUtil.isAssignable(iterator.next(), castType, closure)) { iterator.remove(); } } if (expectedTypes.isEmpty()) expectedTypes.add(castType); } else { expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); } } else { expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); } for (PsiType constraint : expectedTypes) { final PsiType suggestion = GppClosureParameterTypeProvider.getSingleMethodParameterType(constraint, index, closure); if (suggestion != null) { if (GroovyConfigUtils.getInstance().isVersionAtLeast(closure, GroovyConfigUtils.GROOVY2_3)) { if (suggestion instanceof PsiWildcardType && ((PsiWildcardType)suggestion).isSuper()) { return ((PsiWildcardType)suggestion).getBound(); } } return TypesUtil.substituteAndNormalizeType(suggestion, PsiSubstitutor.EMPTY, null, closure); } } return null; }
@NotNull public static PsiClassType getCollectionClassType(@NotNull PsiClassType psiType, @NotNull Project project, @NotNull String qualifiedName) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); final GlobalSearchScope globalsearchscope = GlobalSearchScope.allScope(project); PsiClass genericClass = facade.findClass(qualifiedName, globalsearchscope); if (null != genericClass) { final PsiClassType.ClassResolveResult classResolveResult = psiType.resolveGenerics(); final PsiSubstitutor derivedSubstitutor = classResolveResult.getSubstitutor(); final List<PsiType> typeList = new ArrayList<PsiType>(2); final Map<String, PsiType> nameTypeMap = new HashMap<String, PsiType>(); for (Map.Entry<PsiTypeParameter, PsiType> entry : derivedSubstitutor.getSubstitutionMap().entrySet()) { final PsiType entryValue = entry.getValue(); if (null != entryValue) { nameTypeMap.put(entry.getKey().getName(), entryValue); typeList.add(entryValue); } } PsiSubstitutor genericSubstitutor = PsiSubstitutor.EMPTY; final PsiTypeParameter[] typeParameters = genericClass.getTypeParameters(); for (int i = 0; i < typeParameters.length; i++) { final PsiTypeParameter psiTypeParameter = typeParameters[i]; PsiType mappedType = nameTypeMap.get(psiTypeParameter.getName()); if (null == mappedType && typeList.size() > i) { mappedType = typeList.get(i); } if (null == mappedType) { mappedType = PsiType.getJavaLangObject(PsiManager.getInstance(project), globalsearchscope); } if (mappedType instanceof PsiWildcardType) { mappedType = ((PsiWildcardType) mappedType).getBound(); } genericSubstitutor = genericSubstitutor.put(psiTypeParameter, mappedType); } return elementFactory.createType(genericClass, genericSubstitutor); } return elementFactory.createTypeByFQClassName(qualifiedName, globalsearchscope); }