Search in sources :

Example 31 with Types

use of com.sun.tools.javac.code.Types in project error-prone by google.

the class CollectionIncompatibleType method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    MatchResult directResult = firstNonNullMatchResult(DIRECT_MATCHERS, tree, state);
    MatchResult typeArgResult = null;
    if (directResult == null) {
        typeArgResult = firstNonNullMatchResult(TYPE_ARG_MATCHERS, tree, state);
    }
    if (directResult == null && typeArgResult == null) {
        return Description.NO_MATCH;
    }
    Verify.verify(directResult == null ^ typeArgResult == null);
    MatchResult result = MoreObjects.firstNonNull(directResult, typeArgResult);
    Types types = state.getTypes();
    TypeCompatibilityReport compatibilityReport = EqualsIncompatibleType.compatibilityOfTypes(result.targetType(), result.sourceType(), state);
    if (compatibilityReport.compatible()) {
        return Description.NO_MATCH;
    }
    // For error message, use simple names instead of fully qualified names unless they are
    // identical.
    String sourceTreeType = Signatures.prettyType(ASTHelpers.getType(result.sourceTree()));
    String sourceType = Signatures.prettyType(result.sourceType());
    String targetType = Signatures.prettyType(result.targetType());
    if (sourceType.equals(targetType)) {
        sourceType = result.sourceType().toString();
        targetType = result.targetType().toString();
    }
    Description.Builder description = buildDescription(tree);
    if (typeArgResult != null) {
        description.setMessage(String.format("Argument '%s' should not be passed to this method; its type %s has a type argument " + "%s that is not compatible with its collection's type argument %s", result.sourceTree(), sourceTreeType, sourceType, targetType));
    } else {
        description.setMessage(String.format("Argument '%s' should not be passed to this method; its type %s is not compatible " + "with its collection's type argument %s", result.sourceTree(), sourceType, targetType));
    }
    switch(fixType) {
        case PRINT_TYPES_AS_COMMENT:
            description.addFix(SuggestedFix.prefixWith(tree, String.format("/* expected: %s, actual: %s */", ASTHelpers.getUpperBound(result.targetType(), types), result.sourceType())));
            break;
        case CAST:
            Fix fix;
            if (typeArgResult != null) {
                TypeArgOfMethodArgMatcher matcher = (TypeArgOfMethodArgMatcher) typeArgResult.matcher();
                String fullyQualifiedType = matcher.getMethodArgTypeName();
                String simpleType = Iterables.getLast(Splitter.on('.').split(fullyQualifiedType));
                fix = SuggestedFix.builder().prefixWith(result.sourceTree(), String.format("(%s<?>) ", simpleType)).addImport(fullyQualifiedType).build();
            } else {
                fix = SuggestedFix.prefixWith(result.sourceTree(), "(Object) ");
            }
            description.addFix(fix);
            break;
        case SUPPRESS_WARNINGS:
            SuggestedFix.Builder builder = SuggestedFix.builder();
            builder.prefixWith(result.sourceTree(), String.format("/* expected: %s, actual: %s */ ", targetType, sourceType));
            addSuppressWarnings(builder, state, "CollectionIncompatibleType");
            description.addFix(builder.build());
            break;
        case NONE:
            break;
    }
    return description.build();
}
Also used : Types(com.sun.tools.javac.code.Types) Description(com.google.errorprone.matchers.Description) Fix(com.google.errorprone.fixes.Fix) ProvidesFix(com.google.errorprone.BugPattern.ProvidesFix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) MatchResult(com.google.errorprone.bugpatterns.collectionincompatibletype.AbstractCollectionIncompatibleTypeMatcher.MatchResult) TypeCompatibilityReport(com.google.errorprone.bugpatterns.EqualsIncompatibleType.TypeCompatibilityReport)

Example 32 with Types

use of com.sun.tools.javac.code.Types in project error-prone by google.

the class ComparisonContractViolated method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    if (tree.getBody() == null) {
        return Description.NO_MATCH;
    }
    // Test that the match is in a Comparable.compareTo or Comparator.compare method.
    ClassTree declaringClass = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
    if (!COMPARABLE_CLASS_MATCHER.matches(declaringClass, state) && !COMPARATOR_CLASS_MATCHER.matches(declaringClass, state)) {
        return Description.NO_MATCH;
    }
    if (!COMPARABLE_METHOD_MATCHER.matches(tree, state) && !COMPARATOR_METHOD_MATCHER.matches(tree, state)) {
        return Description.NO_MATCH;
    }
    final Set<ComparisonResult> seenResults = EnumSet.noneOf(ComparisonResult.class);
    final TreeVisitor<Void, VisitorState> visitReturnExpression = new SimpleTreeVisitor<Void, VisitorState>() {

        @Override
        protected Void defaultAction(Tree node, VisitorState state) {
            seenResults.add(node.accept(CONSTANT_VISITOR, state));
            return null;
        }

        @Override
        public Void visitConditionalExpression(ConditionalExpressionTree node, VisitorState state) {
            node.getTrueExpression().accept(this, state);
            node.getFalseExpression().accept(this, state);
            return null;
        }
    };
    tree.getBody().accept(new TreeScanner<Void, VisitorState>() {

        @Override
        public Void visitReturn(ReturnTree node, VisitorState state) {
            return node.getExpression().accept(visitReturnExpression, state);
        }
    }, state);
    if (seenResults.isEmpty() || seenResults.contains(ComparisonResult.NONCONSTANT)) {
        return Description.NO_MATCH;
    }
    if (!seenResults.contains(ComparisonResult.ZERO)) {
        if (tree.getBody().getStatements().size() == 1 && tree.getBody().getStatements().get(0).getKind() == Kind.RETURN) {
            ReturnTree returnTree = (ReturnTree) tree.getBody().getStatements().get(0);
            if (returnTree.getExpression().getKind() == Kind.CONDITIONAL_EXPRESSION) {
                ConditionalExpressionTree condTree = (ConditionalExpressionTree) returnTree.getExpression();
                ExpressionTree conditionExpr = condTree.getCondition();
                conditionExpr = ASTHelpers.stripParentheses(conditionExpr);
                if (!(conditionExpr instanceof BinaryTree)) {
                    return describeMatch(tree);
                }
                ComparisonResult trueConst = condTree.getTrueExpression().accept(CONSTANT_VISITOR, state);
                ComparisonResult falseConst = condTree.getFalseExpression().accept(CONSTANT_VISITOR, state);
                boolean trueFirst;
                if (trueConst == ComparisonResult.NEGATIVE_CONSTANT && falseConst == ComparisonResult.POSITIVE_CONSTANT) {
                    trueFirst = true;
                } else if (trueConst == ComparisonResult.POSITIVE_CONSTANT && falseConst == ComparisonResult.NEGATIVE_CONSTANT) {
                    trueFirst = false;
                } else {
                    return describeMatch(tree);
                }
                switch(conditionExpr.getKind()) {
                    case LESS_THAN:
                    case LESS_THAN_EQUAL:
                        break;
                    case GREATER_THAN:
                    case GREATER_THAN_EQUAL:
                        trueFirst = !trueFirst;
                        break;
                    default:
                        return describeMatch(tree);
                }
                BinaryTree binaryExpr = (BinaryTree) conditionExpr;
                Type ty = ASTHelpers.getType(binaryExpr.getLeftOperand());
                Types types = Types.instance(state.context);
                Symtab symtab = Symtab.instance(state.context);
                ExpressionTree first = trueFirst ? binaryExpr.getLeftOperand() : binaryExpr.getRightOperand();
                ExpressionTree second = trueFirst ? binaryExpr.getRightOperand() : binaryExpr.getLeftOperand();
                String compareType;
                if (types.isSameType(ty, symtab.intType)) {
                    compareType = "Integer";
                } else if (types.isSameType(ty, symtab.longType)) {
                    compareType = "Long";
                } else {
                    return describeMatch(tree);
                }
                return describeMatch(condTree, SuggestedFix.replace(condTree, String.format("%s.compare(%s, %s)", compareType, state.getSourceForNode(first), state.getSourceForNode(second))));
            }
        }
        return describeMatch(tree);
    }
    if (COMPARATOR_METHOD_MATCHER.matches(tree, state) && (seenResults.contains(ComparisonResult.NEGATIVE_CONSTANT) != seenResults.contains(ComparisonResult.POSITIVE_CONSTANT))) {
        // See e.g. com.google.common.collect.Cut.BelowAll.
        return describeMatch(tree);
    } else {
        return Description.NO_MATCH;
    }
}
Also used : Types(com.sun.tools.javac.code.Types) SimpleTreeVisitor(com.sun.source.util.SimpleTreeVisitor) ClassTree(com.sun.source.tree.ClassTree) BinaryTree(com.sun.source.tree.BinaryTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ReturnTree(com.sun.source.tree.ReturnTree) Symtab(com.sun.tools.javac.code.Symtab) Type(com.sun.tools.javac.code.Type) VisitorState(com.google.errorprone.VisitorState) ReturnTree(com.sun.source.tree.ReturnTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 33 with Types

use of com.sun.tools.javac.code.Types in project error-prone by google.

the class EqualsIncompatibleType method compatibilityOfTypes.

public static TypeCompatibilityReport compatibilityOfTypes(Type receiverType, Type argumentType, Set<Type> previousReceiverTypes, Set<Type> previousArgumentTypes, VisitorState state) {
    if (receiverType == null || argumentType == null) {
        return TypeCompatibilityReport.createCompatibleReport();
    }
    // 1.7: java.lang.Object can be cast to primitives (implicitly through the boxed primitive type)
    if (ASTHelpers.isCastable(argumentType, receiverType, state)) {
        return leastUpperBoundGenericMismatch(receiverType, argumentType, previousReceiverTypes, previousArgumentTypes, state);
    }
    // Otherwise, we explore the superclasses of the receiver type as well as the interfaces it
    // implements and we collect all overrides of java.lang.Object.equals(). If one of those
    // overrides is inherited by the argument, then we don't flag the equality test.
    Types types = state.getTypes();
    Predicate<MethodSymbol> equalsPredicate = methodSymbol -> !methodSymbol.isStatic() && ((methodSymbol.flags() & Flags.SYNTHETIC) == 0) && types.isSameType(methodSymbol.getReturnType(), state.getSymtab().booleanType) && methodSymbol.getParameters().size() == 1 && types.isSameType(methodSymbol.getParameters().get(0).type, state.getSymtab().objectType);
    Set<MethodSymbol> overridesOfEquals = ASTHelpers.findMatchingMethods(state.getName("equals"), equalsPredicate, receiverType, types);
    Symbol argumentClass = ASTHelpers.getUpperBound(argumentType, state.getTypes()).tsym;
    for (MethodSymbol method : overridesOfEquals) {
        ClassSymbol methodClass = method.enclClass();
        if (argumentClass.isSubClass(methodClass, types) && !methodClass.equals(state.getSymtab().objectType.tsym) && !methodClass.equals(state.getSymtab().enumSym)) {
            // These should be compatible, but check any generic types for their compatbilities.
            return leastUpperBoundGenericMismatch(receiverType, argumentType, previousReceiverTypes, previousArgumentTypes, state);
        }
    }
    return TypeCompatibilityReport.incompatible(receiverType, argumentType);
}
Also used : Matchers.anyOf(com.google.errorprone.matchers.Matchers.anyOf) Matchers.toType(com.google.errorprone.matchers.Matchers.toType) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Matchers.instanceMethod(com.google.errorprone.matchers.Matchers.instanceMethod) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Signatures(com.google.errorprone.util.Signatures) TypeTag(com.sun.tools.javac.code.TypeTag) Matchers.allOf(com.google.errorprone.matchers.Matchers.allOf) BugPattern(com.google.errorprone.BugPattern) JDK(com.google.errorprone.BugPattern.Category.JDK) Matcher(com.google.errorprone.matchers.Matcher) Matchers.isSameType(com.google.errorprone.matchers.Matchers.isSameType) Tree(com.sun.source.tree.Tree) Nullable(javax.annotation.Nullable) MethodInvocationTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher) ImmutableSet(com.google.common.collect.ImmutableSet) Matchers.staticMethod(com.google.errorprone.matchers.Matchers.staticMethod) Symbol(com.sun.tools.javac.code.Symbol) Set(java.util.Set) Streams(com.google.common.collect.Streams) BOOLEAN_TYPE(com.google.errorprone.suppliers.Suppliers.BOOLEAN_TYPE) Sets(com.google.common.collect.Sets) List(java.util.List) Types(com.sun.tools.javac.code.Types) Predicate(com.google.common.base.Predicate) Description(com.google.errorprone.matchers.Description) AutoValue(com.google.auto.value.AutoValue) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) Flags(com.sun.tools.javac.code.Flags) ASTHelpers(com.google.errorprone.util.ASTHelpers) Type(com.sun.tools.javac.code.Type) Types(com.sun.tools.javac.code.Types) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) Symbol(com.sun.tools.javac.code.Symbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol)

Example 34 with Types

use of com.sun.tools.javac.code.Types in project error-prone by google.

the class FunctionalInterfaceClash method matchClass.

@Override
public Description matchClass(ClassTree tree, VisitorState state) {
    ClassSymbol origin = getSymbol(tree);
    Types types = state.getTypes();
    // collect declared and inherited methods whose signature contains a functional interface
    Multimap<String, MethodSymbol> methods = HashMultimap.create();
    for (Symbol sym : types.membersClosure(getType(tree), /*skipInterface=*/
    false).getSymbols()) {
        if (!(sym instanceof MethodSymbol)) {
            continue;
        }
        if (isBugCheckerSuppressed((MethodSymbol) sym)) {
            continue;
        }
        MethodSymbol msym = (MethodSymbol) sym;
        if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
            continue;
        }
        if (msym.isConstructor() && !msym.owner.equals(origin)) {
            continue;
        }
        methods.put(functionalInterfaceSignature(state, msym), msym);
    }
    // (don't report clashes between inherited members)
    for (Tree member : tree.getMembers()) {
        if (!(member instanceof MethodTree)) {
            continue;
        }
        MethodSymbol msym = getSymbol((MethodTree) member);
        if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
            continue;
        }
        Collection<MethodSymbol> clash = new ArrayList<>(methods.removeAll(functionalInterfaceSignature(state, msym)));
        // Ignore inherited methods that are overridden in the original class. Note that we have to
        // handle transitive inheritance explicitly to handle cases where the visibility of an
        // overridded method is expanded somewhere in the type hierarchy.
        Deque<MethodSymbol> worklist = new ArrayDeque<>();
        worklist.push(msym);
        clash.remove(msym);
        while (!worklist.isEmpty()) {
            MethodSymbol msym2 = worklist.removeFirst();
            ImmutableList<MethodSymbol> overrides = clash.stream().filter(m -> msym2.overrides(m, origin, types, /*checkResult=*/
            false)).collect(toImmutableList());
            worklist.addAll(overrides);
            clash.removeAll(overrides);
        }
        if (!clash.isEmpty()) {
            // ignore if there are overridden clashing methods in class
            if (ASTHelpers.findSuperMethod(msym, types).isPresent() && clash.stream().anyMatch(methodSymbol -> ASTHelpers.findSuperMethod(methodSymbol, types).isPresent())) {
                return NO_MATCH;
            }
            String message = "When passing lambda arguments to this function, callers will need a cast to" + " disambiguate with: " + clash.stream().map(m -> Signatures.prettyMethodSignature(origin, m)).collect(joining("\n    "));
            state.reportMatch(buildDescription(member).setMessage(message).build());
        }
    }
    return NO_MATCH;
}
Also used : Arrays(java.util.Arrays) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher) MethodTree(com.sun.source.tree.MethodTree) DiagnosticPosition(com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition) ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) Multimap(com.google.common.collect.Multimap) Deque(java.util.Deque) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ArrayList(java.util.ArrayList) VisitorState(com.google.errorprone.VisitorState) HashMultimap(com.google.common.collect.HashMultimap) ImmutableList(com.google.common.collect.ImmutableList) Signatures(com.google.errorprone.util.Signatures) BugPattern(com.google.errorprone.BugPattern) JDK(com.google.errorprone.BugPattern.Category.JDK) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Collection(java.util.Collection) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Collectors.joining(java.util.stream.Collectors.joining) List(com.sun.tools.javac.util.List) Types(com.sun.tools.javac.code.Types) CompletionFailure(com.sun.tools.javac.code.Symbol.CompletionFailure) Check(com.sun.tools.javac.comp.Check) Description(com.google.errorprone.matchers.Description) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) ArrayDeque(java.util.ArrayDeque) Collections(java.util.Collections) ASTHelpers(com.google.errorprone.util.ASTHelpers) Type(com.sun.tools.javac.code.Type) Types(com.sun.tools.javac.code.Types) MethodTree(com.sun.source.tree.MethodTree) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) ArrayList(java.util.ArrayList) ArrayDeque(java.util.ArrayDeque) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree)

Example 35 with Types

use of com.sun.tools.javac.code.Types in project error-prone by google.

the class FunctionalInterfaceMethodChanged method matchMethod.

@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(// TypeSymbol to single abstract method of the type
        types::findDescriptorSymbol).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;
}
Also used : Types(com.sun.tools.javac.code.Types) VisitorState(com.google.errorprone.VisitorState) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) Symbol(com.sun.tools.javac.code.Symbol) ClassTree(com.sun.source.tree.ClassTree) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol)

Aggregations

Types (com.sun.tools.javac.code.Types)39 Type (com.sun.tools.javac.code.Type)29 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)10 Tree (com.sun.source.tree.Tree)9 Symbol (com.sun.tools.javac.code.Symbol)9 VisitorState (com.google.errorprone.VisitorState)8 ASTHelpers.getType (com.google.errorprone.util.ASTHelpers.getType)7 ExpressionTree (com.sun.source.tree.ExpressionTree)6 Symtab (com.sun.tools.javac.code.Symtab)6 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)5 Description (com.google.errorprone.matchers.Description)5 ClassTree (com.sun.source.tree.ClassTree)5 MethodTree (com.sun.source.tree.MethodTree)5 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)5 VarSymbol (com.sun.tools.javac.code.Symbol.VarSymbol)5 JavacProcessingEnvironment (com.sun.tools.javac.processing.JavacProcessingEnvironment)5 ArrayList (java.util.ArrayList)5 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)4 List (java.util.List)4 BugPattern (com.google.errorprone.BugPattern)3