@Override public boolean isSubtypeOf(Type superType) { JavaType supType = (JavaType) superType; if (isTagged(ARRAY)) { //Handle covariance of arrays. if(supType.isTagged(ARRAY)) { return ((ArrayType) this).elementType().isSubtypeOf(((ArrayType) supType).elementType()); } //Only possibility to be supertype of array without being an array is to be Object. return "java.lang.Object".equals(supType.fullyQualifiedName()); } else if(isTagged(TYPEVAR)) { return this.equals(superType) || erasure().isSubtypeOf(superType.erasure()); } return false; }
@CheckForNull private static JavaType getPrimitive(JavaType primitiveOrWrapper) { if(primitiveOrWrapper.isPrimitiveWrapper()) { return primitiveOrWrapper.primitiveType(); } return primitiveOrWrapper.isPrimitive() ? primitiveOrWrapper : null; }
public JavaType getUninferedType() { if (uninferedType == null) { return this; } if (uninferedType.isTagged(JavaType.TYPEVAR)) { // produced by a parameterized method where we have not been able to infer return type, so fallback on its leftmost bound return uninferedType.erasure(); } return uninferedType; } }
private boolean isRedundantCast(JavaType cast, JavaType expressionType) { JavaType erasedExpressionType = expressionType; if(erasedExpressionType.isTagged(JavaType.TYPEVAR)) { erasedExpressionType = erasedExpressionType.erasure(); } return erasedExpressionType.equals(cast) || (!(cast instanceof JavaType.ParametrizedTypeJavaType) && !cast.isNumerical() && erasedExpressionType.isSubtypeOf(cast)); }
private JavaType getIteratedObjectType(JavaType type, Set<String> knownTypes) { if (type.isUnknown()) { return Symbols.unknownType; } String fullyQualifiedName = type.fullyQualifiedName(); if (knownTypes.contains(fullyQualifiedName)) { // already visited, early return to avoid loops in type hierarchy return Symbols.unknownType; } knownTypes.add(fullyQualifiedName); if (type.is("java.lang.Iterable")) { if (!type.isParameterized()) { // raw type return symbols.objectType; } ParametrizedTypeJavaType ptjt = (ParametrizedTypeJavaType) type; return ptjt.substitution(ptjt.typeParameters().get(0)); } return type.directSuperTypes().stream() .map(superType -> getIteratedObjectType(superType, knownTypes)) .filter(resolved -> !resolved.isUnknown()) .findFirst().orElse(Symbols.unknownType); }
@Override public boolean isSubtypeOf(Type superType) { JavaType supType = (JavaType) superType; // Handle covariance of arrays. if (supType.isTagged(ARRAY)) { return elementType.isSubtypeOf(((ArrayType) supType).elementType()); } if (supType.isTagged(WILDCARD)) { return ((WildCardType) superType).isSubtypeOfBound(this); } // Only possibility to be supertype of array without being an array is to be Object. return "java.lang.Object".equals(supType.fullyQualifiedName()); }
@Override public boolean isSubtypeOf(String fullyQualifiedName) { if (isTagged(ARRAY)) { return "java.lang.Object".equals(fullyQualifiedName) || (fullyQualifiedName.endsWith("[]") && ((ArrayJavaType) this).elementType.isSubtypeOf(fullyQualifiedName.substring(0, fullyQualifiedName.length() - 2))); } else if (isTagged(TYPEVAR)) { return erasure().isSubtypeOf(fullyQualifiedName); } return false; }
@Override public JavaType erasure() { if (erasure.elementType == null) { erasure.elementType = elementType.erasure(); } return erasure; } }
private static boolean subtypeOfTypeVar(JavaType arg, TypeVariableJavaType formal) { for (JavaType bound : formal.bounds()) { if ((bound.isTagged(JavaType.TYPEVAR) && !subtypeOfTypeVar(arg, (TypeVariableJavaType) bound)) || !arg.isSubtypeOf(bound)) { return false; } } return true; }
private static boolean isValueOfInvocation(ExpressionTree abstractTypedTree) { if (!abstractTypedTree.is(Kind.METHOD_INVOCATION)) { return false; } Type type = abstractTypedTree.symbolType(); MethodMatcher valueOfMatcher = MethodMatcher.create() .typeDefinition(type.fullyQualifiedName()) .name("valueOf") .addParameter(((JavaType) type).primitiveType().fullyQualifiedName()); return valueOfMatcher.matches((MethodInvocationTree) abstractTypedTree); } }
@Nullable private Boolean isOverriding(MethodJavaSymbol overridee, JavaType.ClassJavaType classType) { // same number and type of formal parameters if (getParametersTypes().size() != overridee.getParametersTypes().size()) { return false; } for (int i = 0; i < getParametersTypes().size(); i++) { JavaType paramOverrider = getParametersTypes().get(i); if (paramOverrider.isUnknown()) { // FIXME : complete symbol table should not have unknown types and generics should be handled properly for this. return null; } // Generics type should have same erasure see JLS8 8.4.2 JavaType overrideeType = overridee.getParametersTypes().get(i); if (classType instanceof JavaType.ParametrizedTypeJavaType) { overrideeType = ((JavaType.ParametrizedTypeJavaType) classType).typeSubstitution.substitutedType(overrideeType); if (overrideeType == null) { overrideeType = overridee.getParametersTypes().get(i); } } if (!paramOverrider.erasure().equals(overrideeType.erasure())) { return false; } } // we assume code is compiling so no need to check return type at this point. return true; }
private JavaType getAnonymousClassType(JavaType identifierType, JavaType constructedType, ClassTree classBody) { JavaType parentType = (constructedType.isTagged(JavaType.DEFERRED) || identifierType.symbol().isInterface()) ? identifierType : constructedType; ClassJavaType anonymousClassType = (ClassJavaType) classBody.symbol().type(); if (parentType.getSymbol().isInterface()) { anonymousClassType.interfaces = ImmutableList.of(parentType); anonymousClassType.supertype = symbols.objectType; } else { anonymousClassType.supertype = parentType; anonymousClassType.interfaces = ImmutableList.of(); } anonymousClassType.symbol.members.enter(new JavaSymbol.VariableJavaSymbol(Flags.FINAL, "super", anonymousClassType.supertype, anonymousClassType.symbol)); scan(classBody); return anonymousClassType; }
private JavaType refinedTypeForConstructor(JavaType capturedReturnType, JavaType refinedReturnType) { JavaType sanitizedCaptured = capturedReturnType; JavaType refinedConstructorType = refinedReturnType; if (refinedConstructorType.symbol().isTypeSymbol() && !((JavaSymbol.TypeJavaSymbol) refinedConstructorType.symbol()).typeParameters().scopeSymbols().isEmpty()) { refinedConstructorType = parametrizedTypeCache.getParametrizedTypeType(refinedConstructorType.symbol, new TypeSubstitution()); } if (sanitizedCaptured.isTagged(JavaType.TYPEVAR)) { sanitizedCaptured = ((TypeVariableJavaType) sanitizedCaptured).bounds.get(0); } if (refinedConstructorType.isParameterized()) { refinedConstructorType = resolve.resolveTypeSubstitutionWithDiamondOperator((ParametrizedTypeJavaType) refinedConstructorType, sanitizedCaptured); } return refinedConstructorType; }
private JavaSymbol resolveClassType(Tree tree, Resolve.Env resolveEnv, MemberSelectExpressionTree mse) { resolveAs(mse.expression(), JavaSymbol.TYP, resolveEnv); // member select ending with .class JavaType expressionType = getType(mse.expression()); if (expressionType.isPrimitive()) { expressionType = expressionType.primitiveWrapperType(); } TypeSubstitution typeSubstitution = new TypeSubstitution(); typeSubstitution.add(symbols.classType.getSymbol().typeVariableTypes.get(0), expressionType); JavaType parametrizedClassType = parametrizedTypeCache.getParametrizedTypeType(symbols.classType.symbol, typeSubstitution); registerType(tree, parametrizedClassType); return parametrizedClassType.symbol; }
public boolean isSubtypeOfBound(JavaType type) { switch (boundType) { case SUPER: return bound.isSubtypeOf(type); case EXTENDS: return type.isSubtypeOf(bound); case UNBOUNDED: default: return true; } } }
private static JavaType filterWildcard(JavaType javaType) { if (javaType.isTagged(JavaType.WILDCARD)) { return ((WildCardType) javaType).bound; } return javaType; }
private List<JavaSymbol.MethodJavaSymbol> abstractMethodsOfType(JavaType javaType) { return javaType.symbol().memberSymbols().stream().filter(Resolve::isAbstractMethod).map(JavaSymbol.MethodJavaSymbol.class::cast) .filter(m -> !isObjectMethod(m)) .collect(Collectors.toList()); }
@Override public void visitLambdaExpression(LambdaExpressionTree tree) { LambdaExpressionTreeImpl lambdaExpressionTree = (LambdaExpressionTreeImpl) tree; if (lambdaExpressionTree.isTypeSet()) { // type should be tied to a SAM interface JavaType lambdaType = (JavaType) lambdaExpressionTree.symbolType(); List<JavaType> samMethodArgs = resolve.findSamMethodArgs(lambdaType); for (int i = 0; i < samMethodArgs.size(); i++) { VariableTree param = lambdaExpressionTree.parameters().get(i); if (param.type().is(Tree.Kind.INFERED_TYPE)) { JavaType inferedType = samMethodArgs.get(i); if(inferedType.isTagged(JavaType.WILDCARD)) { // JLS8 18.5.3 inferedType = ((WildCardType) inferedType).bound; } ((AbstractTypedTree) param.type()).setInferedType(inferedType); ((JavaSymbol.VariableJavaSymbol) param.symbol()).type = inferedType; } } super.visitLambdaExpression(tree); if(lambdaType.isUnknown() || lambdaType.isTagged(JavaType.DEFERRED)) { return; } refineLambdaType(lambdaExpressionTree, lambdaType); } else { registerType(tree, symbols.deferedType(lambdaExpressionTree)); } }
private static boolean autoboxing(Type argumentType, Type collectionParameterType) { return argumentType.isPrimitive() && ((JavaType) collectionParameterType).isPrimitiveWrapper() && isSubtypeOf(((JavaType) argumentType).primitiveWrapperType(), collectionParameterType); } }