Search in sources :

Example 41 with VisitorState

use of com.google.errorprone.VisitorState in project error-prone by google.

the class WakelockReleasedDangerously method wakelockMayThrow.

/**
 * Whether the given WakeLock may throw an unexpected RuntimeException when released.
 *
 * <p>Returns true if: 1) the given WakeLock was acquired with timeout, and 2) the given WakeLock
 * is reference counted.
 */
private boolean wakelockMayThrow(Symbol wakelockSymbol, VisitorState state) {
    ClassTree enclosingClass = getTopLevelClass(state);
    ImmutableMultimap<String, MethodInvocationTree> map = methodCallsForSymbol(wakelockSymbol, enclosingClass);
    // Was acquired with timeout.
    return map.get("acquire").stream().anyMatch(m -> m.getArguments().size() == 1) && // Is reference counted, i.e., referenceCounted not explicitly set to false.
    map.get("setReferenceCounted").stream().noneMatch(m -> Boolean.FALSE.equals(constValue(m.getArguments().get(0), Boolean.class)));
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) Matchers.instanceMethod(com.google.errorprone.matchers.Matchers.instanceMethod) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Kind(com.sun.source.tree.Tree.Kind) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) StandardTags(com.google.errorprone.BugPattern.StandardTags) CatchTree(com.sun.source.tree.CatchTree) BugPattern(com.google.errorprone.BugPattern) Category(com.google.errorprone.BugPattern.Category) Matcher(com.google.errorprone.matchers.Matcher) ImmutableMultimap(com.google.common.collect.ImmutableMultimap) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) MethodInvocationTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher) IfTree(com.sun.source.tree.IfTree) UnionClassType(com.sun.tools.javac.code.Type.UnionClassType) ASTHelpers.getReceiver(com.google.errorprone.util.ASTHelpers.getReceiver) ExpressionTree(com.sun.source.tree.ExpressionTree) BugChecker(com.google.errorprone.bugpatterns.BugChecker) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Streams(com.google.common.collect.Streams) ASTHelpers.constValue(com.google.errorprone.util.ASTHelpers.constValue) ASTHelpers.findEnclosingNode(com.google.errorprone.util.ASTHelpers.findEnclosingNode) BodyKind(com.sun.source.tree.LambdaExpressionTree.BodyKind) TreeScanner(com.sun.source.util.TreeScanner) Types(com.sun.tools.javac.code.Types) Description(com.google.errorprone.matchers.Description) MethodMatchers(com.google.errorprone.matchers.method.MethodMatchers) TryTree(com.sun.source.tree.TryTree) ProvidesFix(com.google.errorprone.BugPattern.ProvidesFix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) Builder(com.google.common.collect.ImmutableMultimap.Builder) SeverityLevel(com.google.errorprone.BugPattern.SeverityLevel) ASTHelpers(com.google.errorprone.util.ASTHelpers) Type(com.sun.tools.javac.code.Type) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ClassTree(com.sun.source.tree.ClassTree)

Example 42 with VisitorState

use of com.google.errorprone.VisitorState in project error-prone by google.

the class UnsafeFinalization method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    MethodSymbol sym = ASTHelpers.getSymbol(tree);
    // Match invocations of static native methods.
    if (sym == null || !sym.isStatic() || !Flags.asFlagSet(sym.flags()).contains(Flag.NATIVE)) {
        return NO_MATCH;
    }
    // Find the enclosing method declaration where the invocation occurs.
    MethodTree method = enclosingMethod(state);
    if (method == null) {
        return NO_MATCH;
    }
    // Don't check native methods called from static methods and constructors:
    // static methods don't have an instance to finalize, and we shouldn't need to worry about
    // finalization during construction.
    MethodSymbol enclosing = ASTHelpers.getSymbol(method);
    if (enclosing == null || enclosing.isStatic() || enclosing.isConstructor()) {
        return NO_MATCH;
    }
    // Check if any arguments of the static native method are members (e.g. fields) of the enclosing
    // class. We're only looking for cases where the static native uses state of the enclosing class
    // that may become invalid after finalization.
    ImmutableList<Symbol> arguments = tree.getArguments().stream().map(ASTHelpers::getSymbol).filter(x -> x != null).collect(toImmutableList());
    if (arguments.stream().filter(x -> EnumSet.of(TypeKind.INT, TypeKind.LONG).contains(state.getTypes().unboxedTypeOrType(x.asType()).getKind())).noneMatch(arg -> arg.isMemberOf(enclosing.enclClass(), state.getTypes()))) {
        // no instance state is passed to the native method
        return NO_MATCH;
    }
    if (arguments.stream().anyMatch(arg -> arg.getSimpleName().contentEquals("this") && arg.isMemberOf(enclosing.enclClass(), state.getTypes()))) {
        // the instance is passed to the native method
        return NO_MATCH;
    }
    Symbol finalizeSym = getFinalizer(state, enclosing.enclClass());
    if (finalizeSym.equals(enclosing)) {
        // Don't check native methods called from within the implementation of finalize.
        return NO_MATCH;
    }
    if (finalizeSym.enclClass().equals(state.getSymtab().objectType.asElement())) {
        // Inheriting finalize from Object doesn't count.
        return NO_MATCH;
    }
    boolean[] sawFence = { false };
    new TreeScanner<Void, Void>() {

        @Override
        public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {
            if (FENCE_MATCHER.matches(tree, state)) {
                sawFence[0] = true;
            }
            return null;
        }
    }.scan(state.getPath().getCompilationUnit(), null);
    if (sawFence[0]) {
        // Ignore methods that contain a use of reachabilityFence.
        return NO_MATCH;
    }
    return describeMatch(tree);
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ImmutableList(com.google.common.collect.ImmutableList) BugPattern(com.google.errorprone.BugPattern) Matcher(com.google.errorprone.matchers.Matcher) Tree(com.sun.source.tree.Tree) EnumSet(java.util.EnumSet) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) MethodInvocationTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher) ElementKind(javax.lang.model.element.ElementKind) ExpressionTree(com.sun.source.tree.ExpressionTree) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Flag(com.sun.tools.javac.code.Flags.Flag) Symbol(com.sun.tools.javac.code.Symbol) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Streams(com.google.common.collect.Streams) TypeKind(javax.lang.model.type.TypeKind) TreeScanner(com.sun.source.util.TreeScanner) MethodMatchers.staticMethod(com.google.errorprone.matchers.method.MethodMatchers.staticMethod) Stream(java.util.stream.Stream) Description(com.google.errorprone.matchers.Description) Optional(java.util.Optional) 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) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) Symbol(com.sun.tools.javac.code.Symbol) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ASTHelpers(com.google.errorprone.util.ASTHelpers)

Example 43 with VisitorState

use of com.google.errorprone.VisitorState in project error-prone by google.

the class UnsafeFinalization method getFinalizer.

private static Symbol getFinalizer(VisitorState state, ClassSymbol enclosing) {
    Type finalizerType = state.getTypeFromString("com.google.common.labs.base.Finalizer");
    Optional<VarSymbol> finalizerField = state.getTypes().closure(enclosing.asType()).stream().flatMap(s -> getFields(s.asElement())).filter(s -> ASTHelpers.isSameType(finalizerType, s.asType(), state)).findFirst();
    if (finalizerField.isPresent()) {
        return finalizerField.get();
    }
    return ASTHelpers.resolveExistingMethod(state, enclosing.enclClass(), state.getName("finalize"), /* argTypes= */
    ImmutableList.of(), /* tyargTypes= */
    ImmutableList.of());
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ImmutableList(com.google.common.collect.ImmutableList) BugPattern(com.google.errorprone.BugPattern) Matcher(com.google.errorprone.matchers.Matcher) Tree(com.sun.source.tree.Tree) EnumSet(java.util.EnumSet) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) MethodInvocationTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher) ElementKind(javax.lang.model.element.ElementKind) ExpressionTree(com.sun.source.tree.ExpressionTree) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Flag(com.sun.tools.javac.code.Flags.Flag) Symbol(com.sun.tools.javac.code.Symbol) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Streams(com.google.common.collect.Streams) TypeKind(javax.lang.model.type.TypeKind) TreeScanner(com.sun.source.util.TreeScanner) MethodMatchers.staticMethod(com.google.errorprone.matchers.method.MethodMatchers.staticMethod) Stream(java.util.stream.Stream) Description(com.google.errorprone.matchers.Description) Optional(java.util.Optional) 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) Type(com.sun.tools.javac.code.Type) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol)

Example 44 with VisitorState

use of com.google.errorprone.VisitorState in project error-prone by google.

the class RefasterRuleBuilderScanner method visitMethod.

@Override
public Void visitMethod(MethodTree tree, Void v) {
    try {
        VisitorState state = new VisitorState(context);
        logger.log(FINE, "Discovered method with name {0}", tree.getName());
        if (ASTHelpers.hasAnnotation(tree, Placeholder.class, state)) {
            checkArgument(tree.getModifiers().getFlags().contains(Modifier.ABSTRACT), "@Placeholder methods are expected to be abstract");
            UTemplater templater = new UTemplater(context);
            ImmutableMap.Builder<UVariableDecl, ImmutableClassToInstanceMap<Annotation>> params = ImmutableMap.builder();
            for (VariableTree param : tree.getParameters()) {
                params.put(templater.visitVariable(param, null), UTemplater.annotationMap(ASTHelpers.getSymbol(param)));
            }
            MethodSymbol sym = ASTHelpers.getSymbol(tree);
            placeholderMethods.put(sym, PlaceholderMethod.create(tree.getName(), templater.template(sym.getReturnType()), params.build(), UTemplater.annotationMap(sym)));
        } else if (ASTHelpers.hasAnnotation(tree, BeforeTemplate.class, state)) {
            checkState(afterTemplates.isEmpty(), "BeforeTemplate must come before AfterTemplate");
            Template<?> template = UTemplater.createTemplate(context, tree);
            beforeTemplates.add(template);
            if (template instanceof BlockTemplate) {
                context.put(UTemplater.REQUIRE_BLOCK_KEY, /* data= */
                true);
            }
        } else if (ASTHelpers.hasAnnotation(tree, AfterTemplate.class, state)) {
            afterTemplates.add(UTemplater.createTemplate(context, tree));
        } else if (tree.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
            throw new IllegalArgumentException("Placeholder methods must have @Placeholder, but abstract method does not: " + tree);
        }
        return null;
    } catch (Throwable t) {
        throw new RuntimeException("Error analysing: " + tree.getName(), t);
    }
}
Also used : BeforeTemplate(com.google.errorprone.refaster.annotation.BeforeTemplate) ImmutableClassToInstanceMap(com.google.common.collect.ImmutableClassToInstanceMap) VariableTree(com.sun.source.tree.VariableTree) ImmutableMap(com.google.common.collect.ImmutableMap) BeforeTemplate(com.google.errorprone.refaster.annotation.BeforeTemplate) AfterTemplate(com.google.errorprone.refaster.annotation.AfterTemplate) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) VisitorState(com.google.errorprone.VisitorState)

Example 45 with VisitorState

use of com.google.errorprone.VisitorState 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)

Aggregations

VisitorState (com.google.errorprone.VisitorState)52 Tree (com.sun.source.tree.Tree)31 ASTHelpers (com.google.errorprone.util.ASTHelpers)29 Description (com.google.errorprone.matchers.Description)28 BugPattern (com.google.errorprone.BugPattern)27 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)23 Symbol (com.sun.tools.javac.code.Symbol)23 ClassTree (com.sun.source.tree.ClassTree)22 Type (com.sun.tools.javac.code.Type)22 WARNING (com.google.errorprone.BugPattern.SeverityLevel.WARNING)21 ExpressionTree (com.sun.source.tree.ExpressionTree)21 MethodTree (com.sun.source.tree.MethodTree)21 JDK (com.google.errorprone.BugPattern.Category.JDK)19 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)18 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)16 List (java.util.List)16 NO_MATCH (com.google.errorprone.matchers.Description.NO_MATCH)14 Optional (java.util.Optional)14 VariableTree (com.sun.source.tree.VariableTree)13 ArrayList (java.util.ArrayList)13