This is an automated email from the ASF dual-hosted git repository. jlahoda pushed a commit to branch jdk-javac in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git
commit 755ed65a5c6a8835f40301e95022d7d368f53ce1 Author: Jan Lahoda <jlah...@netbeans.org> AuthorDate: Sun Dec 10 22:31:17 2017 +0100 Improving indexing: producing sig files also for erroneous source files, stripping code of methods. --- java.source.base/nbproject/project.xml | 4 + .../java/source/indexing/VanillaCompileWorker.java | 170 ++++++++++++++++++++- .../source/indexing/VanillaCompileWorkerTest.java | 123 ++++++++++++++- 3 files changed, 284 insertions(+), 13 deletions(-) diff --git a/java.source.base/nbproject/project.xml b/java.source.base/nbproject/project.xml index dcc344b..fa276ea 100644 --- a/java.source.base/nbproject/project.xml +++ b/java.source.base/nbproject/project.xml @@ -336,6 +336,10 @@ <compile-dependency/> </test-dependency> <test-dependency> + <code-name-base>org.netbeans.modules.java.j2seplatform</code-name-base> + <compile-dependency/> + </test-dependency> + <test-dependency> <code-name-base>org.netbeans.modules.java.lexer</code-name-base> <compile-dependency/> </test-dependency> diff --git a/java.source.base/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorker.java b/java.source.base/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorker.java index 1ec005d..73d5570 100644 --- a/java.source.base/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorker.java +++ b/java.source.base/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorker.java @@ -19,14 +19,27 @@ package org.netbeans.modules.java.source.indexing; +import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.PackageTree; import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; import com.sun.tools.javac.api.JavacTaskImpl; -import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; +import com.sun.tools.javac.code.SymbolMetadata; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Type.ForAll; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.code.TypeTag; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.CompileStates.CompileState; import com.sun.tools.javac.comp.Enter; @@ -37,9 +50,11 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCModuleDecl; import com.sun.tools.javac.tree.JCTree.JCPackageDecl; +import com.sun.tools.javac.tree.TreeMaker; import org.netbeans.lib.nbjavac.services.CancelAbort; import org.netbeans.lib.nbjavac.services.CancelService; import com.sun.tools.javac.util.FatalError; +import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import java.io.File; import java.io.IOException; @@ -50,9 +65,11 @@ import java.util.logging.Level; import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic.Kind; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import org.netbeans.api.java.classpath.ClassPath; @@ -189,7 +206,6 @@ final class VanillaCompileWorker extends CompileWorker { boolean aptEnabled = true; Log log = Log.instance(jt.getContext()); JavaCompiler compiler = JavaCompiler.instance(jt.getContext()); - Set<JavaFileObject> haveErrors = new HashSet<>(); JavaFileManager fm = jt.getContext().get(JavaFileManager.class); fm.handleOption(OutputFileManager.OPTION_SET_CURRENT_ROOT, Collections.singleton(context.getRootURI().toString()).iterator()); try { @@ -265,9 +281,7 @@ final class VanillaCompileWorker extends CompileWorker { modifiedTypes.addAll(aTypes); } ExecutableFilesIndex.DEFAULT.setMainClass(context.getRoot().toURL(), active.indexable.getURL(), main[0]); - if (dc.peekDiagnostics(active.jfo).stream().anyMatch(d -> d.getKind() == Kind.ERROR)) { - haveErrors.add(active.jfo); - } + dropMethodsAndErrors(jt.getContext(), unit.getKey()); JavaCustomIndexer.setErrors(context, active, dc); } if (context.isCancelled()) { @@ -285,7 +299,7 @@ final class VanillaCompileWorker extends CompileWorker { for (Element type : types) { TreePath tp = Trees.instance(jtFin).getPath(type); assert tp != null; - log.nerrors = haveErrors.contains(tp.getCompilationUnit().getSourceFile()) ? 1 : 0; + log.nerrors = 0; Iterable<? extends JavaFileObject> generatedFiles = jtFin.generate(Collections.singletonList(type)); CompileTuple unit = clazz2Tuple.get(type); if (unit == null || !unit.virtual) { @@ -360,4 +374,146 @@ final class VanillaCompileWorker extends CompileWorker { } return ParsingOutput.failure(moduleName.name, file2FQNs, addedTypes, addedModules, createdFiles, finished, modifiedTypes, aptGenerated); } + + private void dropMethodsAndErrors(com.sun.tools.javac.util.Context ctx, CompilationUnitTree cut) { + Symtab syms = Symtab.instance(ctx); + TreeMaker make = TreeMaker.instance(ctx); + //TODO: should preserve error types!!! + new TreePathScanner<Void, Void>() { + @Override + public Void visitVariable(VariableTree node, Void p) { + JCTree.JCVariableDecl decl = (JCTree.JCVariableDecl) node; + if ((decl.mods.flags & Flags.ENUM) == 0) { + decl.init = null; + } + if (decl.type.getKind() == TypeKind.ERROR) { + decl.sym.type = decl.type = syms.objectType; + } + clearAnnotations(decl.sym.getMetadata()); + return super.visitVariable(node, p); + } + + @Override + public Void visitMethod(MethodTree node, Void p) { + JCTree.JCMethodDecl decl = (JCTree.JCMethodDecl) node; + Symbol.MethodSymbol msym = decl.sym; + if (Collections.disjoint(msym.getModifiers(), EnumSet.of(Modifier.NATIVE, Modifier.ABSTRACT))) { + JCTree.JCNewClass nct = + make.NewClass(null, + com.sun.tools.javac.util.List.nil(), + make.QualIdent(syms.runtimeExceptionType.tsym), + com.sun.tools.javac.util.List.of(make.Literal("")), + null); + nct.type = syms.runtimeExceptionType; + nct.constructor = syms.runtimeExceptionType.tsym.members().getSymbols( + s -> s.getKind() == ElementKind.CONSTRUCTOR && s.type.getParameterTypes().size() == 1 && s.type.getParameterTypes().head.tsym == syms.stringType.tsym + ).iterator().next(); + decl.body = make.Block(0, com.sun.tools.javac.util.List.of(make.Throw(nct))); + } + Type.MethodType mt; + if (msym.type.hasTag(TypeTag.FORALL)) { + ForAll fa = (ForAll) msym.type; + fa.tvars = error2Object(fa.tvars); + mt = fa.asMethodType(); + } else { + mt = (Type.MethodType) msym.type; + } + mt.restype = error2Object(mt.restype); + mt.argtypes = error2Object(mt.argtypes); + mt.thrown = error2Object(mt.thrown); + clearAnnotations(decl.sym.getMetadata()); + return super.visitMethod(node, p); + } + + @Override + public Void visitClass(ClassTree node, Void p) { + Symbol.ClassSymbol csym = ((JCTree.JCClassDecl) node).sym; + Type.ClassType ct = (Type.ClassType) csym.type; + ct.all_interfaces_field = error2Object(ct.all_interfaces_field); + ct.allparams_field = error2Object(ct.allparams_field); + ct.interfaces_field = error2Object(ct.interfaces_field); + ct.typarams_field = error2Object(ct.typarams_field); + ct.supertype_field = error2Object(ct.supertype_field); + return super.visitClass(node, p); + } + + private void clearAnnotations(SymbolMetadata metadata) { + if (metadata == null) + return; + + //TODO: type annotations, etc. + com.sun.tools.javac.util.List<Attribute.Compound> annotations = metadata.getDeclarationAttributes(); + com.sun.tools.javac.util.List<Attribute.Compound> prev = null; + while (annotations.nonEmpty()) { + if (isErroneous(annotations.head.type)) { + if (prev == null) { + metadata.reset(); + metadata.setDeclarationAttributes(annotations.tail); + } else { + prev.tail = annotations.tail; + } + } + prev = annotations; + annotations = annotations.tail; + } + } + + private boolean isErroneous(TypeMirror type) { + return type == null || type.getKind() == TypeKind.ERROR || type.getKind() == TypeKind.NONE || type.getKind() == TypeKind.OTHER; + } + + private Set<Type> seen = Collections.newSetFromMap(new IdentityHashMap<>()); + + private Type error2Object(Type t) { + if (t == null) + return null; + + if (isErroneous(t)) { + return syms.objectType; + } + + if (!seen.add(t)) + return t; + + switch (t.getKind()) { + case DECLARED: { + resolveErrors((ClassType) t); + break; + } + case WILDCARD: { + Type.WildcardType wt = ((Type.WildcardType) t); + wt.type = error2Object(wt.type); + TypeVar tv = wt.bound; + tv.bound = error2Object(tv.bound); + tv.lower = error2Object(tv.lower); + break; + } + } + return t; + } + + private com.sun.tools.javac.util.List<Type> error2Object(com.sun.tools.javac.util.List<Type> types) { + if (types == null) + return null; + + ListBuffer<Type> lb = new ListBuffer<>(); + boolean changed = false; + for (Type t : types) { + Type nue = error2Object(t); + changed |= nue != t; + lb.append(nue); + } + return changed ? lb.toList() : types; + } + + private void resolveErrors(ClassType ct) { + if (ct.tsym == syms.objectType.tsym) return ; + ct.all_interfaces_field = error2Object(ct.all_interfaces_field); + ct.allparams_field = error2Object(ct.allparams_field); //TODO: should replace with bounds + ct.interfaces_field = error2Object(ct.interfaces_field); + ct.typarams_field = error2Object(ct.typarams_field); + ct.supertype_field = error2Object(ct.supertype_field); + } + }.scan(cut, null); + } } diff --git a/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorkerTest.java b/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorkerTest.java index c2f5ee0..91bb77e 100644 --- a/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorkerTest.java +++ b/java.source.base/test/unit/src/org/netbeans/modules/java/source/indexing/VanillaCompileWorkerTest.java @@ -50,22 +50,133 @@ public class VanillaCompileWorkerTest extends CompileWorkerTestBase { compileTuple("test/Test4.java", "package test; public class Test4 { Undef undef; }")), Arrays.asList(virtualCompileTuple("test/Test1.virtual", "package test; public class Test1 {}"), virtualCompileTuple("test/Test2.virtual", "package test; public class Test2 {}"))); - + assertFalse(result.lowMemory); assertTrue(result.success); - + Set<String> createdFiles = new HashSet<String>(); - + for (File created : result.createdFiles) { createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); } - + //TODO: -// assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test3.sig")), createdFiles); + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test3.sig", + "cache/s1/java/15/classes/test/Test4.sig")), createdFiles); result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; public class Test4 { void t() { Undef undef; } }")), Collections.emptyList()); - + + assertFalse(result.lowMemory); + assertTrue(result.success); + } + + public void testRepair1() throws Exception { + ParsingOutput result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; public class Test4 { public void test() { Undef undef; } }")), + Arrays.asList()); + + assertFalse(result.lowMemory); + assertTrue(result.success); + + Set<String> createdFiles = new HashSet<String>(); + + for (File created : result.createdFiles) { + createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); + } + + //TODO: + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test4.sig")), createdFiles); + } + + public void testRepair2() throws Exception { + ParsingOutput result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; public class Test4 { @Undef public void test1() { } @Deprecated @Undef public void test2() { } }")), + Arrays.asList()); + assertFalse(result.lowMemory); assertTrue(result.success); + + Set<String> createdFiles = new HashSet<String>(); + + for (File created : result.createdFiles) { + createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); + } + + //TODO: + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test4.sig")), createdFiles); + //TODO: check file content!!! + } + + public void testRepair3() throws Exception { + ParsingOutput result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; public class Test4 { public <T> void test1(T t) { } }")), + Arrays.asList()); + + assertFalse(result.lowMemory); + assertTrue(result.success); + + Set<String> createdFiles = new HashSet<String>(); + + for (File created : result.createdFiles) { + createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); + } + + //TODO: + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test4.sig")), createdFiles); + //TODO: check file content!!! + } + + public void testRepair4() throws Exception { + ParsingOutput result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; import java.util.List; public class Test4 { public List<Undef> test() { } }")), + Arrays.asList()); + + assertFalse(result.lowMemory); + assertTrue(result.success); + + Set<String> createdFiles = new HashSet<String>(); + + for (File created : result.createdFiles) { + createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); + } + + //TODO: + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test4.sig")), createdFiles); + //TODO: check file content!!! + } + + public void testRepairEnum() throws Exception { + ParsingOutput result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; public enum Test4 { A {} }")), + Arrays.asList()); + + assertFalse(result.lowMemory); + assertTrue(result.success); + + Set<String> createdFiles = new HashSet<String>(); + + for (File created : result.createdFiles) { + createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); + } + + //TODO: + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test4.sig", + "cache/s1/java/15/classes/test/Test4$1.sig")), + createdFiles); + //TODO: check file content!!! + } + + public void testRepairWildcard() throws Exception { + ParsingOutput result = runIndexing(Arrays.asList(compileTuple("test/Test4.java", "package test; import java.util.*; public class Test4 { void test(List<? extends Undef> l1, List<? super Undef> l2) { } }")), + Arrays.asList()); + + assertFalse(result.lowMemory); + assertTrue(result.success); + + Set<String> createdFiles = new HashSet<String>(); + + for (File created : result.createdFiles) { + createdFiles.add(getWorkDir().toURI().relativize(created.toURI()).getPath()); + } + + //TODO: + assertEquals(new HashSet<String>(Arrays.asList("cache/s1/java/15/classes/test/Test4.sig")), + createdFiles); + //TODO: check file content!!! } } -- To stop receiving notification emails like this one, please contact "comm...@netbeans.apache.org" <comm...@netbeans.apache.org>.