From 768cee3439afd42e81511b2cd81ee369c11ff001 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 20 Oct 2016 15:29:43 +0300 Subject: [PATCH] build javac ast index only when compilation invoked from IDE (re-fix of workaround) --- .../BackwardReferenceIndexWriter.java | 7 +- .../BackwardReferenceRegistrar.java | 5 +- .../builders/impl/java/JavacCompilerTool.java | 6 +- .../ast/JavacReferenceCollectorListener.java | 162 +++++++++++++++++ .../javac/ast/JavacReferencesCollector.java | 168 ++---------------- .../ast/api/JavacFileReferencesRegistrar.java | 3 +- 6 files changed, 184 insertions(+), 167 deletions(-) create mode 100644 jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java index 7f81e6ac7afc..ce1fcd7046e9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceIndexWriter.java @@ -32,7 +32,6 @@ import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.javac.ast.api.JavacRefSymbol; import org.jetbrains.jps.model.java.compiler.JavaCompilers; -import javax.tools.*; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -95,10 +94,6 @@ public class BackwardReferenceIndexWriter { myIndex.close(); } - int enumerateFile(JavaFileObject file) { - return enumeratePath(file.getName()); - } - synchronized LightRef.JavaLightClassRef asClassUsage(Symbol name) { return new LightRef.JavaLightClassRef(myIndex.getByteSeqEum().enumerate(bytes(name))); } @@ -199,7 +194,7 @@ public class BackwardReferenceIndexWriter { } } - private synchronized int enumeratePath(String file) { + synchronized int enumeratePath(String file) { try { return myIndex.getFilePathEnumerator().enumerate(file); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java index 550686a4b92f..f94f62596d35 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java +++ b/jps/jps-builders/src/org/jetbrains/jps/backwardRefs/BackwardReferenceRegistrar.java @@ -21,7 +21,6 @@ import com.sun.tools.javac.code.Type; import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; import org.jetbrains.jps.javac.ast.api.JavacRefSymbol; -import javax.tools.*; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -59,8 +58,8 @@ public class BackwardReferenceRegistrar implements JavacFileReferencesRegistrar } @Override - public void registerFile(JavaFileObject file, Set refs, List defs) { - final int fileId = myWriter.enumerateFile(file); + public void registerFile(String filePath, Set refs, List defs) { + final int fileId = myWriter.enumeratePath(filePath); int funExprId = 0; final List definitions = new ArrayList(defs.size()); diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java index 5afdcd094fe3..8eda00c30343 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/java/JavacCompilerTool.java @@ -16,10 +16,8 @@ package org.jetbrains.jps.builders.impl.java; import com.intellij.util.ExceptionUtil; -import com.sun.source.util.JavacTask; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter; import org.jetbrains.jps.builders.java.CannotCreateJavaCompilerException; import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.javac.JavacMain; @@ -86,8 +84,6 @@ public class JavacCompilerTool extends JavaCompilingTool { @Override public void prepareCompilationTask(@NotNull JavaCompiler.CompilationTask task, @NotNull Collection options) { - if (BackwardReferenceIndexWriter.isEnabled()) { - JavacReferencesCollector.installOn((JavacTask)task); - } + JavacReferencesCollector.installOn(task); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java new file mode 100644 index 000000000000..b6b972f6d62b --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java @@ -0,0 +1,162 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.javac.ast; + +import com.sun.source.tree.Tree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.ClientCodeException; +import com.sun.tools.javac.util.Name; +import gnu.trove.THashSet; +import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; +import org.jetbrains.jps.javac.ast.api.JavacRefSymbol; + +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +final class JavacReferenceCollectorListener implements TaskListener { + private final JavacFileReferencesRegistrar[] myFullASTListeners; + private final JavacFileReferencesRegistrar[] myOnlyImportsListeners; + private final JavacTreeRefScanner myAstScanner; + + private Name myAsterisk; + + private int myRemainDeclarations; + private JCTree.JCCompilationUnit myCurrentCompilationUnit; + private Set myCollectedReferences; + private List myCollectedDefinitions; + + public JavacReferenceCollectorListener(JavacFileReferencesRegistrar[] fullASTListenerArray, JavacFileReferencesRegistrar[] importsListenerArray) { + myFullASTListeners = fullASTListenerArray; + myOnlyImportsListeners = importsListenerArray; + myAstScanner = JavacTreeRefScanner.createASTScanner(); + } + + @Override + public void started(TaskEvent e) { + + } + + @Override + public void finished(TaskEvent e) { + try { + if (e.getKind() == TaskEvent.Kind.ANALYZE) { + // javac creates an event on each processed top level declared class not file + if (myCurrentCompilationUnit != e.getCompilationUnit()) { + myCurrentCompilationUnit = (JCTree.JCCompilationUnit)e.getCompilationUnit(); + myCollectedDefinitions = new ArrayList(); + myCollectedReferences = new THashSet(); + myRemainDeclarations = myCurrentCompilationUnit.getTypeDecls().size() - 1; + scanImports(myCurrentCompilationUnit, myCollectedReferences); + for(JavacFileReferencesRegistrar r: myOnlyImportsListeners) { + r.registerFile(e.getSourceFile().getName(), myCollectedReferences, myCollectedDefinitions); + } + } + else { + myRemainDeclarations--; + } + + JavacTreeScannerSink sink = new JavacTreeScannerSink() { + @Override + public void sinkReference(JavacRefSymbol ref) { + myCollectedReferences.add(ref); + } + + @Override + public void sinkDeclaration(JavacRefSymbol def) { + myCollectedDefinitions.add(def); + } + }; + + if (myFullASTListeners.length != 0) { + TypeElement analyzedElement = e.getTypeElement(); + for (JCTree tree : myCurrentCompilationUnit.getTypeDecls()) { + if (tree.type != null && tree.type.tsym == analyzedElement) { + myAstScanner.scan(tree, sink); + } + } + } + + if (myRemainDeclarations == 0) { + if (myFullASTListeners.length != 0) { + for (JCTree.JCAnnotation annotation : myCurrentCompilationUnit.getPackageAnnotations()) { + myAstScanner.scan(annotation, sink); + } + } + + for(JavacFileReferencesRegistrar r: myFullASTListeners) { + r.registerFile(e.getSourceFile().getName(), myCollectedReferences, myCollectedDefinitions); + } + + myCurrentCompilationUnit = null; + myCollectedDefinitions = null; + myCollectedReferences = null; + } + + } + } + catch (Exception ex) { + throw new ClientCodeException(ex); + } + } + + private Name getAsteriskFromCurrentNameTable(Name tableRepresentative) { + if (myAsterisk == null) { + myAsterisk = tableRepresentative.table.fromChars(new char[]{'*'}, 0, 1); + } + return myAsterisk; + } + + private void scanImports(JCTree.JCCompilationUnit compilationUnit, Set symbols) { + for (JCTree.JCImport anImport : compilationUnit.getImports()) { + final JCTree.JCFieldAccess id = (JCTree.JCFieldAccess)anImport.getQualifiedIdentifier(); + final Symbol sym = id.sym; + if (sym == null) { + final JCTree.JCExpression qExpr = id.getExpression(); + if (qExpr instanceof JCTree.JCFieldAccess) { + final JCTree.JCFieldAccess classImport = (JCTree.JCFieldAccess)qExpr; + final Symbol ownerSym = classImport.sym; + final Name name = id.getIdentifier(); + if (name != getAsteriskFromCurrentNameTable(name)) { + // member import + for (Symbol memberSymbol : ownerSym.members().getElements()) { + if (memberSymbol.getSimpleName() == name) { + symbols.add(new JavacRefSymbol(memberSymbol, Tree.Kind.IMPORT)); + } + } + } + collectClassImports(ownerSym, symbols); + } + } else { + // class import + collectClassImports(sym, symbols); + } + } + } + + private static void collectClassImports(Symbol baseImport, Set collector) { + for (Symbol symbol = baseImport; + symbol != null && symbol.getKind() != ElementKind.PACKAGE; + symbol = symbol.owner) { + collector.add(new JavacRefSymbol(symbol, Tree.Kind.IMPORT)); + } + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java index f461708dfe21..b1a94ea8fe7d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferencesCollector.java @@ -17,29 +17,22 @@ package org.jetbrains.jps.javac.ast; import com.intellij.util.ReflectionUtil; import com.intellij.util.SmartList; -import com.sun.source.tree.Tree; import com.sun.source.util.JavacTask; -import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.util.ClientCodeException; -import com.sun.tools.javac.util.Name; -import gnu.trove.THashSet; import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; -import org.jetbrains.jps.javac.ast.api.JavacRefSymbol; import org.jetbrains.jps.service.JpsServiceManager; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; +import javax.tools.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.List; -import java.util.Set; +/** + * Code here should not depend on any javac private API located in tools.jar if no JavacFileReferencesRegistrar will be run. + * A workaround to allow run standalone jps with improperly configured classloader without NoClassDefFoundError (e.g: IDEA-162877) + */ public class JavacReferencesCollector { - public static void installOn(JavacTask task) { + public static void installOn(JavaCompiler.CompilationTask task) { List fullASTListeners = new SmartList(); List onlyImportsListeners = new SmartList(); for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { @@ -55,149 +48,22 @@ public class JavacReferencesCollector { return; } + JavacTask javacTask = (JavacTask)task; Method addTaskMethod = ReflectionUtil.getMethod(JavacTask.class, "addTaskListener", TaskListener.class); // jdk >= 8 - if (addTaskMethod == null) { - addTaskMethod = ReflectionUtil.getMethod(JavacTask.class, "setTaskListener", TaskListener.class); // jdk 6-7 - } - assert addTaskMethod != null; - - try { - addTaskMethod.invoke(task, new MyTaskListener(fullASTListenerArray, onlyImportsListenerArray)); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - private static final class MyTaskListener implements TaskListener { - private final JavacFileReferencesRegistrar[] myFullASTListeners; - private final JavacFileReferencesRegistrar[] myOnlyImportsListeners; - private final JavacTreeRefScanner myAstScanner; - - private Name myAsterisk; - - private int myRemainDeclarations; - private JCTree.JCCompilationUnit myCurrentCompilationUnit; - private Set myCollectedReferences; - private List myCollectedDefinitions; - - public MyTaskListener(JavacFileReferencesRegistrar[] fullASTListenerArray, JavacFileReferencesRegistrar[] importsListenerArray) { - myFullASTListeners = fullASTListenerArray; - myOnlyImportsListeners = importsListenerArray; - myAstScanner = JavacTreeRefScanner.createASTScanner(); - } - - @Override - public void started(TaskEvent e) { - - } - - @Override - public void finished(TaskEvent e) { + final JavacReferenceCollectorListener taskListener = new JavacReferenceCollectorListener(fullASTListenerArray, onlyImportsListenerArray); + if (addTaskMethod != null) { try { - if (e.getKind() == TaskEvent.Kind.ANALYZE) { - // javac creates an event on each processed top level declared class not file - if (myCurrentCompilationUnit != e.getCompilationUnit()) { - myCurrentCompilationUnit = (JCTree.JCCompilationUnit)e.getCompilationUnit(); - myCollectedDefinitions = new ArrayList(); - myCollectedReferences = new THashSet(); - myRemainDeclarations = myCurrentCompilationUnit.getTypeDecls().size() - 1; - scanImports(myCurrentCompilationUnit, myCollectedReferences); - for(JavacFileReferencesRegistrar r: myOnlyImportsListeners) { - r.registerFile(e.getSourceFile(), myCollectedReferences, myCollectedDefinitions); - } - } - else { - myRemainDeclarations--; - } - - JavacTreeScannerSink sink = new JavacTreeScannerSink() { - @Override - public void sinkReference(JavacRefSymbol ref) { - myCollectedReferences.add(ref); - } - - @Override - public void sinkDeclaration(JavacRefSymbol def) { - myCollectedDefinitions.add(def); - } - }; - - if (myFullASTListeners.length != 0) { - TypeElement analyzedElement = e.getTypeElement(); - for (JCTree tree : myCurrentCompilationUnit.getTypeDecls()) { - if (tree.type != null && tree.type.tsym == analyzedElement) { - myAstScanner.scan(tree, sink); - } - } - } - - if (myRemainDeclarations == 0) { - if (myFullASTListeners.length != 0) { - for (JCTree.JCAnnotation annotation : myCurrentCompilationUnit.getPackageAnnotations()) { - myAstScanner.scan(annotation, sink); - } - } - - for(JavacFileReferencesRegistrar r: myFullASTListeners) { - r.registerFile(e.getSourceFile(), myCollectedReferences, myCollectedDefinitions); - } - - myCurrentCompilationUnit = null; - myCollectedDefinitions = null; - myCollectedReferences = null; - } - - } + addTaskMethod.invoke(task, taskListener); } - catch (Exception ex) { - throw new ClientCodeException(ex); + catch (IllegalAccessException e) { + throw new RuntimeException(e); } - } - - private Name getAsteriskFromCurrentNameTable(Name tableRepresentative) { - if (myAsterisk == null) { - myAsterisk = tableRepresentative.table.fromChars(new char[]{'*'}, 0, 1); + catch (InvocationTargetException e) { + throw new RuntimeException(e); } - return myAsterisk; - } - - private void scanImports(JCTree.JCCompilationUnit compilationUnit, Set symbols) { - for (JCTree.JCImport anImport : compilationUnit.getImports()) { - final JCTree.JCFieldAccess id = (JCTree.JCFieldAccess)anImport.getQualifiedIdentifier(); - final Symbol sym = id.sym; - if (sym == null) { - final JCTree.JCExpression qExpr = id.getExpression(); - if (qExpr instanceof JCTree.JCFieldAccess) { - final JCTree.JCFieldAccess classImport = (JCTree.JCFieldAccess)qExpr; - final Symbol ownerSym = classImport.sym; - final Name name = id.getIdentifier(); - if (name != getAsteriskFromCurrentNameTable(name)) { - // member import - for (Symbol memberSymbol : ownerSym.members().getElements()) { - if (memberSymbol.getSimpleName() == name) { - symbols.add(new JavacRefSymbol(memberSymbol, Tree.Kind.IMPORT)); - } - } - } - collectClassImports(ownerSym, symbols); - } - } else { - // class import - collectClassImports(sym, symbols); - } - } - } - } - - private static void collectClassImports(Symbol baseImport, Set collector) { - for (Symbol symbol = baseImport; - symbol != null && symbol.getKind() != ElementKind.PACKAGE; - symbol = symbol.owner) { - collector.add(new JavacRefSymbol(symbol, Tree.Kind.IMPORT)); + } else { + // jdk 6-7 + javacTask.setTaskListener(taskListener); } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java index b03f0e1e813e..b586b577b847 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileReferencesRegistrar.java @@ -15,7 +15,6 @@ */ package org.jetbrains.jps.javac.ast.api; -import javax.tools.*; import java.util.List; import java.util.Set; @@ -25,5 +24,5 @@ public interface JavacFileReferencesRegistrar { boolean onlyImports(); - void registerFile(JavaFileObject file, Set refs, List defs); + void registerFile(String filePath, Set refs, List defs); }