private GuardedBySymbolResolver( ClassSymbol enclosingClass, CompilationUnitTree compilationUnit, Context context, Tree leaf) { this.compilationUnit = (JCCompilationUnit) compilationUnit; this.enclosingClass = enclosingClass; this.context = context; this.types = Types.instance(context); this.decl = leaf; }
boolean isKnownCheckedException(VisitorState state, Type type) { Types types = state.getTypes(); Symtab symtab = state.getSymtab(); // Check erasure for generics. type = types.erasure(type); return // Has to be some Exception: A variable of type Throwable might be an Error. types.isSubtype(type, symtab.exceptionType) // Has to be some subtype: A variable of type Exception might be a RuntimeException. && !types.isSameType(type, symtab.exceptionType) // Can't be of type RuntimeException. && !types.isSubtype(type, symtab.runtimeExceptionType); } };
private static boolean isAssignableTo(Type type, Supplier<Type> supplier, VisitorState state) { Type to = supplier.get(state); if (to == null) { // the type couldn't be loaded return false; } to = state.getTypes().erasure(to); return state.getTypes().isAssignable(type, to); }
/** Returns true if {@code erasure(s) == erasure(t)}. */ public static boolean isSameType(Type s, Type t, VisitorState state) { if (s == null || t == null) { return false; } Types types = state.getTypes(); return types.isSameType(types.erasure(s), types.erasure(t)); }
/** Returns true if {@code erasure(s)} is castable to {@code erasure(t)}. */ public static boolean isCastable(Type s, Type t, VisitorState state) { if (s == null || t == null) { return false; } Types types = state.getTypes(); return types.isCastable(types.erasure(s), types.erasure(t)); }
static boolean equivalentExprs(Unifier unifier, JCExpression expr1, JCExpression expr2) { return expr1.type != null && expr2.type != null && Types.instance(unifier.getContext()).isSameType(expr2.type, expr1.type) && expr2.toString().equals(expr1.toString()); }
@Override public Description matchMethodInvocation( MethodInvocationTree methodInvocationTree, VisitorState visitorState) { if (!TO_ARRAY_MATCHER.matches(methodInvocationTree, visitorState)) { return NO_MATCH; } Types types = visitorState.getTypes(); Type variableType = types.elemtype(getType(getOnlyElement(methodInvocationTree.getArguments()))); if (variableType == null) { return NO_MATCH; } Type collectionType = types.asSuper( ASTHelpers.getReceiverType(methodInvocationTree), visitorState.getSymbolFromString("java.util.Collection")); List<Type> typeArguments = collectionType.getTypeArguments(); if (!typeArguments.isEmpty() && !types.isCastable( types.erasure(variableType), types.erasure(getOnlyElement(typeArguments)))) { return describeMatch(methodInvocationTree); } return NO_MATCH; } }
/** Returns true if {@code erasure(s) <: erasure(t)}. */ public static boolean isSubtype(Type s, Type t, VisitorState state) { if (s == null || t == null) { return false; } if (SUBTYPE_UNDEFINED.contains(s.getTag()) || SUBTYPE_UNDEFINED.contains(t.getTag())) { return false; } Types types = state.getTypes(); return types.isSubtype(types.erasure(s), types.erasure(t)); }
/** * Given an {@link ExpressionTree} that represents an argument of array type, rewrites it to wrap * it in a call to either {@link java.util.Arrays#hashCode} if it is single dimensional, or {@link * java.util.Arrays#deepHashCode} if it is multidimensional. */ private static String rewriteArrayArgument(ExpressionTree arg, VisitorState state) { Types types = state.getTypes(); Type argType = ASTHelpers.getType(arg); Preconditions.checkState(types.isArray(argType), "arg must be of array type"); if (types.isArray(types.elemtype(argType))) { return "Arrays.deepHashCode(" + state.getSourceForNode(arg) + ")"; } else { return "Arrays.hashCode(" + state.getSourceForNode(arg) + ")"; } } }
Type type = getType(exception); do { type = state.getTypes().supertype(type); exceptionsBySuper.put(type.tsym, exception); } while (!state.getTypes().isSameType(type, state.getSymtab().objectType));
/** Removes the message argument if it is present. */ private void removeMessageArgumentIfPresent(VisitorState state, List<Type> argumentTypes) { if (argumentTypes.size() == 2) { return; } Types types = state.getTypes(); Type firstType = argumentTypes.get(0); if (types.isSameType(firstType, state.getSymtab().stringType)) { argumentTypes.remove(0); } }
private boolean isCheckedException(Type type) { return !state.getTypes().isAssignable(type, state.getSymtab().errorType) && !state.getTypes().isAssignable(type, state.getSymtab().runtimeExceptionType); } }
void validateAnnotationType(DiagnosticPosition pos, Type type) { if (type.isPrimitive()) return; if (types.isSameType(type, syms.stringType)) return; if ((type.tsym.flags() & Flags.ENUM) != 0) return; if ((type.tsym.flags() & Flags.ANNOTATION) != 0) return; if (types.lowerBound(type).tsym == syms.classType.tsym) return; if (types.isArray(type) && !types.isArray(types.elemtype(type))) { validateAnnotationType(pos, types.elemtype(type)); return; } log.error(pos, "invalid.annotation.member.type"); }
if (!types.isArray(varargsArgumentType) || !types.elemtype(varargsArgumentType).isPrimitive()) { return false; return !(types.isSameType(varargsParamType, varargsArgumentType) || types.isSameType(varargsParamType.getComponentType(), varargsArgumentType));
/** Gets a human-friendly name for the given {@link Symbol} to use in diagnostics. */ public String getPrettyName(Symbol sym) { if (!sym.getSimpleName().isEmpty()) { return sym.getSimpleName().toString(); } if (sym.getKind() == ElementKind.ENUM) { // anonymous classes for enum constants are identified by the enclosing constant // declaration return sym.owner.getSimpleName().toString(); } // anonymous classes have an empty name, but a recognizable superclass or interface // e.g. refer to `new Runnable() { ... }` as "Runnable" Type superType = state.getTypes().supertype(sym.type); if (state.getTypes().isSameType(superType, state.getSymtab().objectType)) { superType = Iterables.getFirst(state.getTypes().interfaces(sym.type), superType); } return superType.tsym.getSimpleName().toString(); }
private static Stream<MethodSymbol> findSuperMethods( MethodSymbol methodSymbol, Types types, boolean skipInterfaces) { TypeSymbol owner = (TypeSymbol) methodSymbol.owner; return types.closure(owner.type).stream() .filter(closureTypes -> skipInterfaces ? !closureTypes.isInterface() : true) .map(type -> findSuperMethodInType(methodSymbol, type, types)) .filter(Objects::nonNull); }
@Override public Description matchMethod(MethodTree tree, VisitorState state) { ClassTree enclosingClazz = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class); if (tree.getModifiers().getFlags().contains(Modifier.DEFAULT) && IS_FUNCTIONAL_INTERFACE.matches(enclosingClazz, state)) { Types types = Types.instance(state.context); Set<Symbol> functionalSuperInterfaceSams = enclosingClazz.getImplementsClause().stream() .filter(t -> IS_FUNCTIONAL_INTERFACE.matches(t, state)) .map(ASTHelpers::getSymbol) .map(TypeSymbol.class::cast) .map(types::findDescriptorSymbol) // TypeSymbol to single abstract method of the type .collect(toImmutableSet()); // We designate an override of a superinterface SAM "behavior preserving" if it just // calls the SAM of this interface. Symbol thisInterfaceSam = types.findDescriptorSymbol(ASTHelpers.getSymbol(enclosingClazz)); // relatively crude: doesn't verify that the same args are passed in the same order // so it can get false positives for behavior-preservingness (false negatives for the check) TreeVisitor<Boolean, VisitorState> behaviorPreserving = new BehaviorPreservingChecker(thisInterfaceSam); if (!Collections.disjoint( ASTHelpers.findSuperMethods(ASTHelpers.getSymbol(tree), types), functionalSuperInterfaceSams) && !tree.accept(behaviorPreserving, state)) { return describeMatch(tree); } } return Description.NO_MATCH; }
private static boolean isSubtype(Types types, Type t, Type s) { return s != null && types.isSubtype(t, s); }
/** * Return true if this parameter is assignable to the target parameter. This will consider * subclassing, autoboxing and null. */ boolean isAssignableTo(Parameter target, VisitorState state) { if (state.getTypes().isSameType(type(), Type.noType) || state.getTypes().isSameType(target.type(), Type.noType)) { return false; } try { return state.getTypes().isAssignable(type(), target.type()); } catch (CompletionFailure e) { // Report completion errors to avoid e.g. https://github.com/bazelbuild/bazel/issues/4105 Check.instance(state.context) .completionError((DiagnosticPosition) state.getPath().getLeaf(), e); return false; } }