build javac ast index only when compilation invoked from IDE (re-fix of workaround)

This commit is contained in:
Dmitry Batkovich
2016-10-20 15:30:18 +03:00
parent 595352343d
commit 768cee3439
6 changed files with 184 additions and 167 deletions
@@ -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);
}
@@ -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<JavacRefSymbol> refs, List<JavacRefSymbol> defs) {
final int fileId = myWriter.enumerateFile(file);
public void registerFile(String filePath, Set<JavacRefSymbol> refs, List<JavacRefSymbol> defs) {
final int fileId = myWriter.enumeratePath(filePath);
int funExprId = 0;
final List<LightRef> definitions = new ArrayList<LightRef>(defs.size());
@@ -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<String> options) {
if (BackwardReferenceIndexWriter.isEnabled()) {
JavacReferencesCollector.installOn((JavacTask)task);
}
JavacReferencesCollector.installOn(task);
}
}
@@ -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<JavacRefSymbol> myCollectedReferences;
private List<JavacRefSymbol> 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<JavacRefSymbol>();
myCollectedReferences = new THashSet<JavacRefSymbol>();
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<JavacRefSymbol> 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<JavacRefSymbol> collector) {
for (Symbol symbol = baseImport;
symbol != null && symbol.getKind() != ElementKind.PACKAGE;
symbol = symbol.owner) {
collector.add(new JavacRefSymbol(symbol, Tree.Kind.IMPORT));
}
}
}
@@ -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<JavacFileReferencesRegistrar> fullASTListeners = new SmartList<JavacFileReferencesRegistrar>();
List<JavacFileReferencesRegistrar> onlyImportsListeners = new SmartList<JavacFileReferencesRegistrar>();
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<JavacRefSymbol> myCollectedReferences;
private List<JavacRefSymbol> 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<JavacRefSymbol>();
myCollectedReferences = new THashSet<JavacRefSymbol>();
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<JavacRefSymbol> 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<JavacRefSymbol> 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);
}
}
}
@@ -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<JavacRefSymbol> refs, List<JavacRefSymbol> defs);
void registerFile(String filePath, Set<JavacRefSymbol> refs, List<JavacRefSymbol> defs);
}