Search in sources :

Example 6 with TreeScanner

use of com.sun.source.util.TreeScanner in project error-prone by google.

the class InconsistentCapitalization method matchClass.

@Override
public Description matchClass(ClassTree tree, VisitorState state) {
    ImmutableSet<Symbol> fields = FieldScanner.findFields(tree);
    if (fields.isEmpty()) {
        return Description.NO_MATCH;
    }
    ImmutableMap<String, Symbol> fieldNamesMap = fields.stream().collect(toImmutableMap(symbol -> symbol.toString().toLowerCase(), identity()));
    ImmutableMap<TreePath, Symbol> matchedParameters = MatchingParametersScanner.findMatchingParameters(fieldNamesMap, state.getPath());
    if (matchedParameters.isEmpty()) {
        return Description.NO_MATCH;
    }
    for (Entry<TreePath, Symbol> entry : matchedParameters.entrySet()) {
        TreePath parameterPath = entry.getKey();
        Symbol field = entry.getValue();
        String fieldName = field.getSimpleName().toString();
        VariableTree parameterTree = (VariableTree) parameterPath.getLeaf();
        SuggestedFix.Builder fix = SuggestedFix.builder().merge(SuggestedFixes.renameVariable(parameterTree, fieldName, state));
        if (parameterPath.getParentPath() != null) {
            String qualifiedName = getExplicitQualification(parameterPath, tree, state) + field.getSimpleName();
            // If the field was accessed in a non-qualified way, by renaming the parameter this may
            // cause clashes with it. Thus, it is required to qualify all uses of the field within the
            // parameter's scope just in case.
            parameterPath.getParentPath().getLeaf().accept(new TreeScanner<Void, Void>() {

                @Override
                public Void visitIdentifier(IdentifierTree tree, Void unused) {
                    if (field.equals(ASTHelpers.getSymbol(tree))) {
                        fix.replace(tree, qualifiedName);
                    }
                    return null;
                }
            }, null);
        }
        state.reportMatch(buildDescription(parameterPath.getLeaf()).setMessage(String.format("Found the field '%s' with the same name as the parameter '%s' but with " + "different capitalization.", fieldName, ((VariableTree) parameterPath.getLeaf()).getName())).addFix(fix.build()).build());
    }
    return Description.NO_MATCH;
}
Also used : SuggestedFixes(com.google.errorprone.fixes.SuggestedFixes) TreePath(com.sun.source.util.TreePath) ImmutableSet(com.google.common.collect.ImmutableSet) ElementKind(javax.lang.model.element.ElementKind) ImmutableMap(com.google.common.collect.ImmutableMap) ClassTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher) Symbol(com.sun.tools.javac.code.Symbol) VariableTree(com.sun.source.tree.VariableTree) TreeScanner(com.sun.source.util.TreeScanner) VisitorState(com.google.errorprone.VisitorState) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) Description(com.google.errorprone.matchers.Description) IdentifierTree(com.sun.source.tree.IdentifierTree) Function.identity(java.util.function.Function.identity) Entry(java.util.Map.Entry) BugPattern(com.google.errorprone.BugPattern) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) ProvidesFix(com.google.errorprone.BugPattern.ProvidesFix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) JDK(com.google.errorprone.BugPattern.Category.JDK) TreePathScanner(com.sun.source.util.TreePathScanner) Tree(com.sun.source.tree.Tree) ASTHelpers(com.google.errorprone.util.ASTHelpers) ClassTree(com.sun.source.tree.ClassTree) Symbol(com.sun.tools.javac.code.Symbol) VariableTree(com.sun.source.tree.VariableTree) IdentifierTree(com.sun.source.tree.IdentifierTree) TreePath(com.sun.source.util.TreePath) SuggestedFix(com.google.errorprone.fixes.SuggestedFix)

Example 7 with TreeScanner

use of com.sun.source.util.TreeScanner in project error-prone by google.

the class StreamResourceLeak method addFix.

@Override
protected void addFix(Description.Builder description, ExpressionTree tree, VisitorState state) {
    TreePath parentPath = state.getPath().getParentPath();
    Tree parent = parentPath.getLeaf();
    SuggestedFix.Builder fix = SuggestedFix.builder();
    String streamType = SuggestedFixes.prettyType(state, fix, ASTHelpers.getReturnType(tree));
    if (parent instanceof MemberSelectTree) {
        StatementTree statement = state.findEnclosing(StatementTree.class);
        if (statement instanceof VariableTree) {
            // Variables need to be declared outside the try-with-resources:
            // e.g. `int count = Files.lines(p).count();`
            // -> `int count; try (Stream<String> stream = Files.lines(p)) { count = stream.count(); }`
            VariableTree var = (VariableTree) statement;
            int pos = ((JCTree) var).getStartPosition();
            int initPos = ((JCTree) var.getInitializer()).getStartPosition();
            int eqPos = pos + state.getSourceForNode(var).substring(0, initPos - pos).lastIndexOf('=');
            fix.replace(eqPos, initPos, String.format(";\ntry (%s stream = %s) {\n%s =", streamType, state.getSourceForNode(tree), var.getName().toString()));
        } else {
            // the non-variable case, e.g. `return Files.lines(p).count()`
            // -> try (Stream<Stream> stream = Files.lines(p)) { return stream.count(); }`
            fix.prefixWith(statement, String.format("try (%s stream = %s) {\n", streamType, state.getSourceForNode(tree)));
        }
        fix.replace(tree, "stream");
        fix.postfixWith(statement, "}");
        description.addFix(fix.build());
    } else if (parent instanceof VariableTree) {
        // If the stream is assigned to a variable, wrap the variable in a try-with-resources
        // that includes all statements in the same block that reference the variable.
        Tree grandParent = parentPath.getParentPath().getLeaf();
        if (!(grandParent instanceof BlockTree)) {
            return;
        }
        List<? extends StatementTree> statements = ((BlockTree) grandParent).getStatements();
        int idx = statements.indexOf(parent);
        int lastUse = idx;
        for (int i = idx + 1; i < statements.size(); i++) {
            boolean[] found = { false };
            statements.get(i).accept(new TreeScanner<Void, Void>() {

                @Override
                public Void visitIdentifier(IdentifierTree tree, Void unused) {
                    if (Objects.equals(ASTHelpers.getSymbol(tree), ASTHelpers.getSymbol(parent))) {
                        found[0] = true;
                    }
                    return null;
                }
            }, null);
            if (found[0]) {
                lastUse = i;
            }
        }
        fix.prefixWith(parent, "try (");
        fix.replace(state.getEndPosition(((VariableTree) parent).getInitializer()), state.getEndPosition(parent), ") {");
        fix.postfixWith(statements.get(lastUse), "}");
        description.addFix(fix.build());
    } else if (parent instanceof EnhancedForLoopTree) {
        // If the stream is used in a loop (e.g. directory streams), wrap the loop in
        // try-with-resources.
        fix.prefixWith(parent, String.format("try (%s stream = %s) {\n", streamType, state.getSourceForNode(tree)));
        fix.replace(tree, "stream");
        fix.postfixWith(parent, "}");
        description.addFix(fix.build());
    } else if (parent instanceof MethodInvocationTree) {
        // If the stream is used in a method that is called in an expression statement, wrap it in
        // try-with-resources.
        Tree grandParent = parentPath.getParentPath().getLeaf();
        if (!(grandParent instanceof ExpressionStatementTree)) {
            return;
        }
        fix.prefixWith(parent, String.format("try (%s stream = %s) {\n", streamType, state.getSourceForNode(tree)));
        fix.replace(tree, "stream");
        fix.postfixWith(grandParent, "}");
        description.addFix(fix.build());
    }
}
Also used : MemberSelectTree(com.sun.source.tree.MemberSelectTree) VariableTree(com.sun.source.tree.VariableTree) JCTree(com.sun.tools.javac.tree.JCTree) IdentifierTree(com.sun.source.tree.IdentifierTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) StatementTree(com.sun.source.tree.StatementTree) TreePath(com.sun.source.util.TreePath) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) TreeScanner(com.sun.source.util.TreeScanner) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) JCTree(com.sun.tools.javac.tree.JCTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) BlockTree(com.sun.source.tree.BlockTree) List(java.util.List) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree)

Example 8 with TreeScanner

use of com.sun.source.util.TreeScanner 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 9 with TreeScanner

use of com.sun.source.util.TreeScanner in project ceylon-compiler by ceylon.

the class TestPos method main.

public static void main(String... args) throws IOException {
    final boolean[] sawError = { false };
    final StringBuilder log = new StringBuilder();
    class MyFileObject extends SimpleJavaFileObject {

        MyFileObject() {
            super(URI.create("myfo:///Test.java"), SOURCE);
        }

        @Override
        public String getCharContent(boolean ignoreEncodingErrors) {
            // 0123456789012345678901234567890123456789012345678901234
            return "class Test { { Object[] o = new <T,e,s,t>Object[0]; } }";
        }
    }
    class Scanner extends TreeScanner<Void, Trees> {

        CompilationUnitTree toplevel = null;

        @Override
        public Void visitCompilationUnit(CompilationUnitTree node, Trees trees) {
            toplevel = node;
            return super.visitCompilationUnit(node, trees);
        }

        @Override
        public Void visitErroneous(ErroneousTree node, Trees trees) {
            sawError[0] = true;
            long startPos = trees.getSourcePositions().getStartPosition(toplevel, node);
            long endPos = trees.getSourcePositions().getEndPosition(toplevel, node);
            log.append(String.format("begin=%s, end=%s : %s%n", startPos, endPos, node.getErrorTrees()));
            if (startPos != 28)
                error("Start pos for %s is incorrect (%s)!", node, startPos);
            if (endPos != 50)
                error("End pos for %s is incorrect (%s)!", node, endPos);
            return null;
        }
    }
    JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
    List<JavaFileObject> compilationUnits = Collections.<JavaFileObject>singletonList(new MyFileObject());
    DiagnosticListener<JavaFileObject> dl = new DiagnosticListener<JavaFileObject>() {

        public void report(Diagnostic<? extends JavaFileObject> diag) {
            log.append(String.format("%s @ %s%n", diag.getCode(), diag.getPosition()));
            if (!diag.getCode().equals(errCode))
                error("unexpected error");
            if (diag.getPosition() != 33)
                error("Error pos for %s is incorrect (%s)!", diag.getCode(), diag.getPosition());
            sawError[0] = true;
        }
    };
    JavacTask task = (JavacTask) javac.getTask(null, null, dl, null, null, compilationUnits);
    Trees trees = Trees.instance(task);
    Iterable<? extends Tree> toplevels = task.parse();
    if (!sawError[0])
        error("No parse error detected");
    sawError[0] = false;
    new Scanner().scan(toplevels, trees);
    if (!sawError[0])
        error("No error tree detected");
    if (!log.toString().equals(expected))
        error("Unexpected log message: %n%s%n", log);
    System.out.print(log);
    System.out.flush();
}
Also used : SimpleJavaFileObject(javax.tools.SimpleJavaFileObject) Trees(com.sun.source.util.Trees) TreeScanner(com.sun.source.util.TreeScanner) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) JavaCompiler(javax.tools.JavaCompiler) Diagnostic(javax.tools.Diagnostic) DiagnosticListener(javax.tools.DiagnosticListener) SimpleJavaFileObject(javax.tools.SimpleJavaFileObject) JavaFileObject(javax.tools.JavaFileObject) TreeScanner(com.sun.source.util.TreeScanner) ErroneousTree(com.sun.source.tree.ErroneousTree) JavacTask(com.sun.source.util.JavacTask)

Aggregations

TreeScanner (com.sun.source.util.TreeScanner)9 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)5 Tree (com.sun.source.tree.Tree)5 IdentifierTree (com.sun.source.tree.IdentifierTree)4 Symbol (com.sun.tools.javac.code.Symbol)4 BugPattern (com.google.errorprone.BugPattern)3 WARNING (com.google.errorprone.BugPattern.SeverityLevel.WARNING)3 VisitorState (com.google.errorprone.VisitorState)3 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)3 Description (com.google.errorprone.matchers.Description)3 ASTHelpers (com.google.errorprone.util.ASTHelpers)3 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)3 VariableTree (com.sun.source.tree.VariableTree)3 VarSymbol (com.sun.tools.javac.code.Symbol.VarSymbol)3 ImmutableList (com.google.common.collect.ImmutableList)2 Streams (com.google.common.collect.Streams)2 JDK (com.google.errorprone.BugPattern.Category.JDK)2 MethodInvocationTreeMatcher (com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher)2 NO_MATCH (com.google.errorprone.matchers.Description.NO_MATCH)2 Matcher (com.google.errorprone.matchers.Matcher)2