Commits

Jan Lahoda committed c69e43c

Support for statements.

  • Participants
  • Parent commits c7fbe9b

Comments (0)

Files changed (8)

api/nbproject/project.xml

                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.api.java.classpath</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>

api/src/org/netbeans/modules/jackpot30/impl/Utilities.java

 
 import com.sun.source.tree.AnnotationTree;
 import com.sun.source.tree.AssignmentTree;
+import com.sun.source.tree.ErroneousTree;
+import com.sun.source.tree.ExpressionStatementTree;
 import com.sun.source.tree.ExpressionTree;
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.LiteralTree;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.NewArrayTree;
+import com.sun.source.tree.Scope;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.annotations.common.NonNull;
 import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.TreeMaker;
 import org.netbeans.modules.jackpot30.spi.ClassPathBasedHintProvider;
 import org.netbeans.modules.jackpot30.spi.HintDescription;
 import org.netbeans.modules.jackpot30.spi.HintProvider;
+import org.netbeans.modules.java.source.JavaSourceAccessor;
+import org.netbeans.modules.java.source.transform.ImmutableTreeTranslator;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.openide.util.Lookup;
 import org.openide.util.NbCollections;
         return result;
     }
     
+    public static Tree parseAndAttribute(CompilationInfo info, String pattern, Scope scope) {
+        Tree patternTree = info.getTreeUtilities().parseExpression(pattern, new SourcePositions[1]);
+        boolean expression = true;
+
+        if (patternTree.getKind() == Kind.ERRONEOUS || (patternTree.getKind() == Kind.IDENTIFIER && ((IdentifierTree) patternTree).getName().contentEquals("<error>"))) { //TODO: <error>...
+            patternTree = info.getTreeUtilities().parseStatement(pattern, new SourcePositions[1]);
+            expression = false;
+        }
+
+        FixTree fixTree = new FixTree();
+
+        fixTree.attach(JavaSourceAccessor.getINSTANCE().getJavacTask(info).getContext());
+        
+        patternTree = fixTree.translate(patternTree);
+
+        if (scope == null) {
+            return patternTree;
+        }
+
+        TypeMirror type = info.getTreeUtilities().attributeTree(patternTree, scope);
+
+        if (isError(type) && expression) {
+            //maybe type?
+            if (Utilities.isPureMemberSelect(patternTree, false) && info.getElements().getTypeElement(pattern) != null) {
+                Tree var = info.getTreeUtilities().parseExpression(pattern + ".class;", new SourcePositions[1]);
+
+                type = info.getTreeUtilities().attributeTree(var, scope);
+
+                Tree typeTree = ((MemberSelectTree) var).getExpression();
+
+                if (!isError(info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), typeTree)))) {
+                    patternTree = typeTree;
+                }
+            }
+        }
+
+        return patternTree;
+    }
+    
+    private static boolean isError(Element el) {
+        return (el == null || (el.getKind() == ElementKind.CLASS) && isError(((TypeElement) el).asType()));
+    }
+
+    private static boolean isError(TypeMirror type) {
+        return type == null || type.getKind() == TypeKind.ERROR;
+    }
+
+    private static final class FixTree extends ImmutableTreeTranslator {
+
+        @Override
+        public Tree translate(Tree tree) {
+            if (tree != null && tree.getKind() == Kind.EXPRESSION_STATEMENT) {
+                ExpressionStatementTree et = (ExpressionStatementTree) tree;
+
+                if (et.getExpression().getKind() == Kind.ERRONEOUS) {
+                    ErroneousTree err = (ErroneousTree) et.getExpression();
+
+                    if (err.getErrorTrees().size() == 1 && err.getErrorTrees().get(0).getKind() == Kind.IDENTIFIER) {
+                        IdentifierTree idTree = (IdentifierTree) err.getErrorTrees().get(0);
+                        CharSequence id = idTree.getName().toString();
+
+                        if (id.length() > 0 && id.charAt(0) == '$') {
+                            return make.ExpressionStatement(idTree);
+                        }
+                    }
+                }
+            }
+            return super.translate(tree);
+        }
+
+    }
+
+    public static CharSequence getWildcardTreeName(@NonNull Tree t) {
+        if (t.getKind() == Kind.EXPRESSION_STATEMENT && ((ExpressionStatementTree) t).getExpression().getKind() == Kind.IDENTIFIER) {
+            IdentifierTree identTree = (IdentifierTree) ((ExpressionStatementTree) t).getExpression();
+            
+            return identTree.getName().toString();
+        }
+
+        return null;
+    }
+
 }

api/src/org/netbeans/modules/jackpot30/impl/pm/BulkSearch.java

 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.modules.jackpot30.impl.Utilities;
 
 /**
  *
         int i = 0;
 
         for (String c : code) {
-            Tree t = info.getTreeUtilities().parseExpression(c, new SourcePositions[1]);
-
-            if (t.getKind() == Kind.ERRONEOUS || (t.getKind() == Kind.IDENTIFIER && ((IdentifierTree) t).getName().contentEquals("<error>"))) { //TODO: <error>...
-                t = info.getTreeUtilities().parseStatement(c, new SourcePositions[1]);
-            }
-
-            patterns[i++] = t;
+            patterns[i++] = Utilities.parseAndAttribute(info, c, null);
         }
 
         int[] groups = TreeSerializer.serializePatterns(ser, patterns);

api/src/org/netbeans/modules/jackpot30/impl/pm/CopyFinder.java

             }
         }
 
+        if (p != null && Utilities.getWildcardTreeName(p.getLeaf()) != null) {
+            String ident = Utilities.getWildcardTreeName(p.getLeaf()).toString();
+
+            if (ident.startsWith("$") && StatementTree.class.isAssignableFrom(node.getKind().asInterface())) {
+                TreePath currentPath = new TreePath(getCurrentPath(), node);
+                variables.put(ident, currentPath);
+                return true;
+            }
+        }
+
         if (p != null && sameKind(node, p.getLeaf())) {
             //maybe equivalent:
             boolean result = superScan(node, p) == Boolean.TRUE;

api/src/org/netbeans/modules/jackpot30/impl/pm/Pattern.java

             return null;
         }
 
-        Tree patternTree = info.getTreeUtilities().parseExpression(pattern, new SourcePositions[1]);
-        TypeMirror type = info.getTreeUtilities().attributeTree(patternTree, scope[0]);
-
-        if (isError(type)) {
-            //maybe type?
-            if (Utilities.isPureMemberSelect(patternTree, false) && info.getElements().getTypeElement(pattern) != null) {
-                Tree var = info.getTreeUtilities().parseExpression(pattern + ".class;", new SourcePositions[1]);
-
-                type = info.getTreeUtilities().attributeTree(var, scope[0]);
-
-                Tree typeTree = ((MemberSelectTree) var).getExpression();
-
-                if (!isError(info.getTrees().getElement(new TreePath(new TreePath(info.getCompilationUnit()), typeTree)))) {
-                    patternTree = typeTree;
-                }
-            }
-        }
-
-        if (isError(type)) {
-            //or statement?
-            //XXX: how to verify?
-            patternTree = info.getTreeUtilities().parseStatement(pattern, new SourcePositions[1]);
-            type = info.getTreeUtilities().attributeTree(patternTree, scope[0]);
-        }
-
-        return patternTree;
+        return Utilities.parseAndAttribute(info, pattern, scope[0]);
     }
 
-    private static boolean isError(Element el) {
-        return (el == null || (el.getKind() == ElementKind.CLASS) && isError(((TypeElement) el).asType()));
-    }
-    
-    private static boolean isError(TypeMirror type) {
-        return type == null || type.getKind() == TypeKind.ERROR;
-    }
-    
     private static final class ScannerImpl extends TreePathScanner<Scope, CompilationInfo> {
 
         @Override

api/src/org/netbeans/modules/jackpot30/spi/JavaFix.java

 package org.netbeans.modules.jackpot30.spi;
 
 import com.sun.javadoc.Tag;
+import com.sun.source.tree.ExpressionStatementTree;
 import com.sun.source.tree.VariableTree;
 import java.io.IOException;
 import java.util.regex.Matcher;
                         return super.visitVariable(node, p);
                     }
 
+                    @Override
+                    public Void visitExpressionStatement(ExpressionStatementTree node, Void p) {
+                        String name = Utilities.getWildcardTreeName(node).toString();
+
+                        if (name != null) {
+                            TreePath tp = parameters.get(name);
+
+                            if (tp != null) {
+                                wc.rewrite(node, tp.getLeaf());
+                                return null;
+                            }
+                        }
+                        
+                        return super.visitExpressionStatement(node, p);
+                    }
+
                 }.scan(new TreePath(new TreePath(tp.getCompilationUnit()), parsed), null);
 
                 wc.rewrite(tp.getLeaf(), parsed);

api/test/unit/src/org/netbeans/modules/jackpot30/impl/hints/HintsInvokerTest.java

                             "}\n",
                             "4:9-6:10:verifier:HINT");
     }
-    
+
     public void testPatternFalseOccurrence() throws Exception {
         performAnalysisTest("test/Test.java",
                             "|package test;\n" +
                             "}\n");
     }
 
+    public void testStatementVariables() throws Exception {
+        performFixTest("test/Test.java",
+                       "|package test;\n" +
+                       "\n" +
+                       "public class Test {\n" +
+                       "     private int test(java.io.File f) {\n" +
+                       "         if (true)\n" +
+                       "             System.err.println(1);\n" +
+                       "         else\n" +
+                       "             System.err.println(2);\n" +
+                       "     }\n" +
+                       "}\n",
+                       "4:9-7:35:verifier:HINT",
+                       "FixImpl",
+                       ("package test;\n" +
+                       "\n" +
+                       "public class Test {\n" +
+                       "     private int test(java.io.File f) {\n" +
+                       "         if (!true)\n" +
+                       "             System.err.println(2);\n" +
+                       "         else\n" +
+                       "             System.err.println(1);\n" +
+                       "     }\n" +
+                       "}\n").replaceAll("[ \t\n]+", " "));
+    }
+
     private static final Map<String, HintDescription> test2Hint;
 
     static {
         test2Hint.put("testPatternAssert1", HintDescriptionFactory.create().setTriggerPattern(PatternDescription.create("assert $1 : $2;", constraints)).setWorker(new WorkerImpl()).produce());
         test2Hint.put("testPatternStatementAndSingleStatementBlockAreSame", HintDescriptionFactory.create().setTriggerPattern(PatternDescription.create("if ($1) return $2;", Collections.<String, String>emptyMap())).setWorker(new WorkerImpl()).produce());
         test2Hint.put("testPatternFalseOccurrence", HintDescriptionFactory.create().setTriggerPattern(PatternDescription.create("$1.toURL()", Collections.singletonMap("$1", "java.io.File"))).setWorker(new WorkerImpl()).produce());
+        test2Hint.put("testStatementVariables", HintDescriptionFactory.create().setTriggerPattern(PatternDescription.create("if ($1) $2; else $3;", constraints)).setWorker(new WorkerImpl("if (!$1) $3 else $2")).produce());
     }
 
     @Override

api/test/unit/src/org/netbeans/modules/jackpot30/impl/pm/CopyFinderTest.java

                              new Pair[] {new Pair<String, String>("$1", "x")});
     }
 
+    public void testStatementVariables() throws Exception {
+        performVariablesTest("package test; public class Test {public int test1() { if (true) return 1; else return 2; } }",
+                             "if ($1) $2; else $3;",
+                             new Pair[] {
+                                  new Pair<String, int[]>("$1", new int[] {89 - 31, 93 - 31}),
+                                  new Pair<String, int[]>("$2", new int[] {95 - 31, 104 - 31}),
+                                  new Pair<String, int[]>("$3", new int[] {110 - 31, 119 - 31})
+                             },
+                             new Pair[0]);
+    }
+
     protected void performVariablesTest(String code, String pattern, Pair<String, int[]>[] duplicatesPos, Pair<String, String>[] duplicatesNames) throws Exception {
         prepareTest(code, -1);