mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
JPS: support javac inlined constants in incremental java compilation
GitOrigin-RevId: 42977fcc81ef1fcf21dbb46f37e0d5435946ea49
This commit is contained in:
committed by
intellij-monorepo-bot
parent
60b4249d3d
commit
425460b641
+1
-1
@@ -42,7 +42,7 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" assert-keyword="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" assert-keyword="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<component name="ProjectResources">
|
||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
Generated
+1
-1
@@ -6,7 +6,7 @@
|
||||
<component name="ProjectResources">
|
||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
Generated
+1
-1
@@ -6,7 +6,7 @@
|
||||
<component name="ProjectResources">
|
||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
+3
-5
@@ -5,16 +5,14 @@ Compiling files:
|
||||
src/Server.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/ConstantChain/Client.class
|
||||
out/production/ConstantChain/ServerClient.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
src/ServerClient.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/ConstantChain/Server.class
|
||||
out/production/ConstantChain/Client.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Server.java
|
||||
End of files
|
||||
src/Client.java
|
||||
End of files
|
||||
+7
-5
@@ -5,14 +5,16 @@ Compiling files:
|
||||
src/A.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/ConstantChain1/A.class
|
||||
out/production/ConstantChain1/B.class
|
||||
out/production/ConstantChain1/C.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/B.java
|
||||
src/C.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/ConstantChain1/Client.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/A.java
|
||||
src/B.java
|
||||
src/C.java
|
||||
src/Client.java
|
||||
End of files
|
||||
End of files
|
||||
+6
-4
@@ -7,12 +7,14 @@ src/Client.java
|
||||
src/Const1.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/ConstantChain2/Client.class
|
||||
out/production/ConstantChain2/Const1.class
|
||||
out/production/ConstantChain2/Const2.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
src/Const1.java
|
||||
src/Const2.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/ConstantChain2/Client.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
End of files
|
||||
+1
-13
@@ -5,26 +5,14 @@ Compiling files:
|
||||
moduleA/src/a/A.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/moduleA/a/A.class
|
||||
out/production/moduleA/a/AA.class
|
||||
End of files
|
||||
Compiling files:
|
||||
moduleA/src/a/A.java
|
||||
moduleA/src/a/AA.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/moduleB/b/B.class
|
||||
out/production/moduleB/b/BB.class
|
||||
End of files
|
||||
Compiling files:
|
||||
moduleB/src/b/B.java
|
||||
moduleB/src/b/BB.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/moduleC/c/C.class
|
||||
out/production/moduleC/c/CC.class
|
||||
End of files
|
||||
Compiling files:
|
||||
moduleC/src/c/C.java
|
||||
moduleC/src/c/CC.java
|
||||
End of files
|
||||
End of files
|
||||
+1
-4
@@ -7,10 +7,7 @@ src/Server.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/InnerConstantChange/Client.class
|
||||
out/production/InnerConstantChange/Server$Inner.class
|
||||
out/production/InnerConstantChange/Server.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
src/Server.java
|
||||
End of files
|
||||
End of files
|
||||
+12
-4
@@ -6,11 +6,19 @@ src/constants/B.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/MutualConstants/constants/A.class
|
||||
out/production/MutualConstants/constants/B.class
|
||||
out/production/MutualConstants/constants/PrintConst.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/constants/A.java
|
||||
src/constants/B.java
|
||||
src/constants/PrintConst.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/MutualConstants/constants/B.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/constants/B.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/MutualConstants/constants/PrintConst.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/constants/PrintConst.java
|
||||
End of files
|
||||
+1
-3
@@ -6,9 +6,7 @@ src/Server.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/StringConstantLessAccessible/Client.class
|
||||
out/production/StringConstantLessAccessible/Server.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
src/Server.java
|
||||
End of files
|
||||
End of files
|
||||
@@ -6,9 +6,7 @@ src/Server.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/RecompileDependent/Client.class
|
||||
out/production/RecompileDependent/Server.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
src/Server.java
|
||||
End of files
|
||||
End of files
|
||||
+1
-3
@@ -6,15 +6,13 @@ src/Server.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/RecompileDependentTests/Client.class
|
||||
out/production/RecompileDependentTests/Server.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/Client.java
|
||||
src/Server.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/test/RecompileDependentTests/TestClient.class
|
||||
End of files
|
||||
Compiling files:
|
||||
testSrc/TestClient.java
|
||||
End of files
|
||||
End of files
|
||||
+1
-5
@@ -5,12 +5,8 @@ Compiling files:
|
||||
src/bug/Namespace.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/PackageInfoRecompileOnConstantChange/bug/Ann.class
|
||||
out/production/PackageInfoRecompileOnConstantChange/bug/Namespace.class
|
||||
out/production/PackageInfoRecompileOnConstantChange/bug/package-info.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/bug/Ann.java
|
||||
src/bug/Namespace.java
|
||||
src/bug/package-info.java
|
||||
End of files
|
||||
End of files
|
||||
@@ -16,6 +16,7 @@ import javax.lang.model.util.Types;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class Javac8RefScanner extends JavacTreeRefScanner {
|
||||
|
||||
@Override
|
||||
public Tree visitLambdaExpression(LambdaExpressionTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) {
|
||||
final TypeMirror type = refCollector.getType(node);
|
||||
@@ -23,7 +24,7 @@ public class Javac8RefScanner extends JavacTreeRefScanner {
|
||||
if (types != null && type != null) {
|
||||
final Element element = types.asElement(type);
|
||||
if (element != null) {
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(element);
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), element);
|
||||
if (ref != null) {
|
||||
refCollector.sinkDeclaration(new JavacDef.JavacFunExprDef(ref));
|
||||
}
|
||||
@@ -36,14 +37,14 @@ public class Javac8RefScanner extends JavacTreeRefScanner {
|
||||
public Tree visitMemberReference(MemberReferenceTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) {
|
||||
final Element element = refCollector.getReferencedElement(node);
|
||||
if (element != null) {
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(element);
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), element);
|
||||
if (ref != null) {
|
||||
refCollector.sinkReference(ref);
|
||||
}
|
||||
}
|
||||
final TypeMirror type = refCollector.getType(node);
|
||||
if (type != null) {
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(refCollector.getTypeUtility().asElement(type));
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), refCollector.getTypeUtility().asElement(type));
|
||||
if (ref != null) {
|
||||
refCollector.sinkDeclaration(new JavacDef.JavacFunExprDef(ref));
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@ public class JavacMain {
|
||||
}
|
||||
else {
|
||||
diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buildCompilerErrorMessage(e)));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+2
-4
@@ -22,7 +22,7 @@ import org.jetbrains.jps.javac.DiagnosticOutputConsumer;
|
||||
import org.jetbrains.jps.javac.JavaCompilerToolExtension;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileData;
|
||||
|
||||
import javax.tools.*;
|
||||
import javax.tools.JavaCompiler;
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class AbstractRefCollectorCompilerToolExtension extends JavaCompilerToolExtension {
|
||||
@@ -32,7 +32,7 @@ public abstract class AbstractRefCollectorCompilerToolExtension extends JavaComp
|
||||
@NotNull Collection<String> options,
|
||||
@NotNull final DiagnosticOutputConsumer diagnosticConsumer) {
|
||||
if (compilingTool.isCompilerTreeAPISupported() && isEnabled()) {
|
||||
JavacReferenceCollector.installOn(task, divideImportsRefs(), new Consumer<JavacFileData>() {
|
||||
JavacReferenceCollector.installOn(task, new Consumer<JavacFileData>() {
|
||||
@Override
|
||||
public void consume(JavacFileData data) {
|
||||
diagnosticConsumer.registerJavacFileData(data);
|
||||
@@ -42,6 +42,4 @@ public abstract class AbstractRefCollectorCompilerToolExtension extends JavaComp
|
||||
}
|
||||
|
||||
protected abstract boolean isEnabled();
|
||||
|
||||
protected abstract boolean divideImportsRefs();
|
||||
}
|
||||
|
||||
-5
@@ -17,15 +17,10 @@ package org.jetbrains.jps.javac.ast;
|
||||
|
||||
public class ExternalRefCollectorCompilerToolExtension extends AbstractRefCollectorCompilerToolExtension {
|
||||
public static final String ENABLED_PARAM = "external.java.process.ref.collector.enabled";
|
||||
public static final String DIVIDE_IMPORTS_PARAM = "external.java.process.divide.imports";
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return "true".equals(System.getProperty(ENABLED_PARAM));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean divideImportsRefs() {
|
||||
return "true".equals(System.getProperty(DIVIDE_IMPORTS_PARAM));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.jetbrains.jps.javac.ast;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileData;
|
||||
|
||||
import javax.tools.*;
|
||||
import javax.tools.JavaCompiler;
|
||||
|
||||
/**
|
||||
* Code here should not depend on any javac private API located in tools.jar if no JavacFileReferencesRegistrar-s will be run.
|
||||
@@ -26,8 +26,7 @@ import javax.tools.*;
|
||||
*/
|
||||
public class JavacReferenceCollector {
|
||||
public static void installOn(JavaCompiler.CompilationTask task,
|
||||
boolean divideImportRefs,
|
||||
Consumer<? super JavacFileData> fileDataConsumer) {
|
||||
JavacReferenceCollectorListener.installOn(task, divideImportRefs, fileDataConsumer);
|
||||
JavacReferenceCollectorListener.installOn(task, fileDataConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
+42
-39
@@ -9,10 +9,7 @@ import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.javac.ast.api.*;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
@@ -21,15 +18,9 @@ import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
final class JavacReferenceCollectorListener implements TaskListener {
|
||||
private final static TObjectIntHashMap<JavacRef> EMPTY_T_OBJ_INT_MAP = new TObjectIntHashMap<JavacRef>(0);
|
||||
|
||||
private final boolean myDivideImportRefs;
|
||||
private final Consumer<? super JavacFileData> myDataConsumer;
|
||||
private final JavacTask myJavacTask;
|
||||
private final JavacTreeRefScanner myAstScanner;
|
||||
@@ -43,9 +34,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
|
||||
private final Map<String, ReferenceCollector> myIncompletelyProcessedFiles = new HashMap<String, ReferenceCollector>(10);
|
||||
|
||||
static void installOn(JavaCompiler.CompilationTask task,
|
||||
boolean divideImportRefs,
|
||||
Consumer<? super JavacFileData> dataConsumer) {
|
||||
static void installOn(JavaCompiler.CompilationTask task, Consumer<? super JavacFileData> dataConsumer) {
|
||||
JavacTask javacTask = (JavacTask)task;
|
||||
Method addTaskMethod; // jdk >= 8
|
||||
try {
|
||||
@@ -54,10 +43,9 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
catch (NoSuchMethodException e) {
|
||||
addTaskMethod = null;
|
||||
}
|
||||
final JavacReferenceCollectorListener taskListener = new JavacReferenceCollectorListener(divideImportRefs,
|
||||
dataConsumer,
|
||||
javacTask,
|
||||
addTaskMethod != null);
|
||||
final JavacReferenceCollectorListener taskListener = new JavacReferenceCollectorListener(
|
||||
dataConsumer, javacTask, addTaskMethod != null
|
||||
);
|
||||
if (addTaskMethod != null) {
|
||||
try {
|
||||
addTaskMethod.setAccessible(true);
|
||||
@@ -75,11 +63,9 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
}
|
||||
}
|
||||
|
||||
private JavacReferenceCollectorListener(boolean divideImportRefs,
|
||||
Consumer<? super JavacFileData> dataConsumer,
|
||||
private JavacReferenceCollectorListener(Consumer<? super JavacFileData> dataConsumer,
|
||||
JavacTask javacTask,
|
||||
boolean atLeastJdk8) {
|
||||
myDivideImportRefs = divideImportRefs;
|
||||
myDataConsumer = dataConsumer;
|
||||
myJavacTask = javacTask;
|
||||
myAtLeastJdk8 = atLeastJdk8;
|
||||
@@ -133,9 +119,6 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
|
||||
if (collectImportsData) {
|
||||
scanImports(unit, incompletelyProcessedFile.myFileData.getRefs(), incompletelyProcessedFile);
|
||||
if (myDivideImportRefs) {
|
||||
scanImports(unit, incompletelyProcessedFile.myFileData.getImportRefs(), incompletelyProcessedFile);
|
||||
}
|
||||
}
|
||||
myAstScanner.scan(declarationToProcess, incompletelyProcessedFile);
|
||||
|
||||
@@ -176,7 +159,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
// member import
|
||||
for (Element memberElement : myElementUtility.getAllMembers((TypeElement)ownerElement)) {
|
||||
if (memberElement.getSimpleName() == name) {
|
||||
incrementOrAdd(elements, JavacRef.JavacElementRefBase.fromElement(memberElement, null, myNameTableCache, importProps));
|
||||
incrementOrAdd(elements, JavacRef.JavacElementRefBase.fromElement(null, memberElement, null, myNameTableCache, importProps));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +176,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
for (Element element = baseImport;
|
||||
element != null && element.getKind() != ElementKind.PACKAGE;
|
||||
element = element.getEnclosingElement()) {
|
||||
incrementOrAdd(collector, JavacRef.JavacElementRefBase.fromElement(element, null, myNameTableCache, importProps));
|
||||
incrementOrAdd(collector, JavacRef.JavacElementRefBase.fromElement(null, element, null, myNameTableCache, importProps));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,18 +184,34 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
private final JavacFileData myFileData;
|
||||
private final JavacTreeHelper myTreeHelper;
|
||||
private int myRemainDeclarations;
|
||||
|
||||
private final JavacRef.JavacClass myPackageInfo;
|
||||
|
||||
private ReferenceCollector(int remainDeclarations,
|
||||
String filePath,
|
||||
CompilationUnitTree unitTree) {
|
||||
myRemainDeclarations = remainDeclarations;
|
||||
myFileData = new JavacFileData(filePath,
|
||||
createReferenceHolder(),
|
||||
myDivideImportRefs ? createReferenceHolder() : EMPTY_T_OBJ_INT_MAP,
|
||||
new ArrayList<JavacTypeCast>(),
|
||||
createDefinitionHolder(),
|
||||
new THashSet<JavacRef>());
|
||||
myFileData = new JavacFileData(
|
||||
filePath, createReferenceHolder(), new ArrayList<JavacTypeCast>(), createDefinitionHolder(), new THashSet<JavacRef>()
|
||||
);
|
||||
myTreeHelper = new JavacTreeHelper(unitTree, myTreeUtility);
|
||||
|
||||
if (isPackageInfo(filePath)) {
|
||||
final ExpressionTree packageName = unitTree.getPackageName();
|
||||
final String pack = packageName != null ? packageName.toString() : "";
|
||||
myPackageInfo = new JavacRef.JavacClassImpl(false, Collections.<Modifier>emptySet(), pack.isEmpty()? "package-info" : pack + ".package-info");
|
||||
sinkDeclaration(new JavacDef.JavacClassDef(myPackageInfo, JavacRef.EMPTY_ARRAY));
|
||||
}
|
||||
else {
|
||||
myPackageInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPackageInfo(String filePath) {
|
||||
if (filePath != null && filePath.endsWith("package-info.java")) {
|
||||
final int idx = filePath.length() - "package-info.java".length() - 1;
|
||||
return idx >= 0 && (filePath.charAt(idx) == '/' || filePath.charAt(idx) == File.separatorChar);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sinkReference(@Nullable JavacRef.JavacElementRefBase ref) {
|
||||
@@ -234,21 +233,25 @@ final class JavacReferenceCollectorListener implements TaskListener {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
JavacRef.JavacElementRefBase asJavacRef(Element element) {
|
||||
return asJavacRef(element, null);
|
||||
JavacRef.JavacElementRefBase asJavacRef(final Element containingClass, Element element) {
|
||||
return asJavacRef(containingClass, element, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
JavacRef.JavacElementRefBase asJavacRef(Element element, Element qualifier) {
|
||||
return JavacRef.JavacElementRefBase.fromElement(element, qualifier, myNameTableCache);
|
||||
JavacRef.JavacElementRefBase asJavacRef(final Element containingClass, Element element, Element qualifier) {
|
||||
return JavacRef.JavacElementRefBase.fromElement(getContainingClassName(containingClass), element, qualifier, myNameTableCache);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
JavacRef.JavacElementRefBase asJavacRef(TypeMirror typeMirror) {
|
||||
JavacRef.JavacElementRefBase asJavacRef(final Element containingClass, TypeMirror typeMirror) {
|
||||
final Element element = getTypeUtility().asElement(typeMirror);
|
||||
return element == null ? null : JavacRef.JavacElementRefBase.fromElement(element, null, myNameTableCache);
|
||||
return element == null ? null : JavacRef.JavacElementRefBase.fromElement(getContainingClassName(containingClass), element, null, myNameTableCache);
|
||||
}
|
||||
|
||||
private String getContainingClassName(Element containingClass) {
|
||||
return containingClass != null? myNameTableCache.parseBinaryName(containingClass) : myPackageInfo != null? myPackageInfo.getName() : null;
|
||||
}
|
||||
|
||||
Element getReferencedElement(Tree tree) {
|
||||
return myTreeHelper.getReferencedElement(tree);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
return null;
|
||||
}
|
||||
if (ALLOWED_ELEMENTS.contains(element.getKind())) {
|
||||
refCollector.sinkReference(refCollector.asJavacRef(element));
|
||||
refCollector.sinkReference(refCollector.asJavacRef(getCurrentEnclosingTypeElement(), element));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
if (node.getClassBody() == null) {
|
||||
final Element element = collector.getReferencedElement(node);
|
||||
if (element != null) {
|
||||
collector.sinkReference(collector.asJavacRef(element));
|
||||
collector.sinkReference(collector.asJavacRef(getCurrentEnclosingTypeElement(), element));
|
||||
}
|
||||
return super.visitNewClass(node, collector);
|
||||
} else {
|
||||
@@ -74,7 +74,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
public Tree visitVariable(VariableTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) {
|
||||
final Element element = refCollector.getReferencedElement(node);
|
||||
if (element != null && element.getKind() == ElementKind.FIELD) {
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(element);
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), element);
|
||||
if (ref != null) {
|
||||
processMemberDefinition(refCollector, ref, element, element.asType());
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
if (type instanceof DeclaredType) {
|
||||
qualifierType = ((DeclaredType)type).asElement();
|
||||
}
|
||||
refCollector.sinkReference(refCollector.asJavacRef(element, qualifierType));
|
||||
refCollector.sinkReference(refCollector.asJavacRef(getCurrentEnclosingTypeElement(), element, qualifierType));
|
||||
}
|
||||
return super.visitMemberSelect(node, refCollector);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(element);
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), element);
|
||||
if (ref != null) {
|
||||
processMemberDefinition(refCollector, ref, element, ((ExecutableElement)element).getReturnType());
|
||||
}
|
||||
@@ -124,7 +124,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
Set<TypeElement> typeElements = extractImplicitToStringCalls(lOp, rOp, collector);
|
||||
if (typeElements != null) {
|
||||
for (TypeElement element : typeElements) {
|
||||
JavacRef.JavacElementRefBase ref = collector.asJavacRef(element);
|
||||
JavacRef.JavacElementRefBase ref = collector.asJavacRef(getCurrentEnclosingTypeElement(), element);
|
||||
if (ref != null) {
|
||||
collector.sinkImplicitToString(ref);
|
||||
}
|
||||
@@ -151,7 +151,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
retType = typeArguments.get(0);
|
||||
}
|
||||
}
|
||||
final JavacRef.JavacElementRefBase returnType = refCollector.asJavacRef(retType);
|
||||
final JavacRef.JavacElementRefBase returnType = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), retType);
|
||||
if (returnType != null) {
|
||||
refCollector.sinkDeclaration(new JavacDef.JavacMemberDef(ref, returnType, dimension, isStatic(element)));
|
||||
}
|
||||
@@ -164,13 +164,13 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
if (element != null && element.getKind() != ElementKind.CONSTRUCTOR) {
|
||||
Set<Modifier> modifiers = element.getModifiers();
|
||||
if (!modifiers.contains(Modifier.STATIC) && !modifiers.contains(Modifier.PRIVATE)) {
|
||||
TypeElement currentClass = myCurrentEnclosingElement.peek();
|
||||
final TypeElement currentClass = getCurrentEnclosingTypeElement();
|
||||
TypeElement actualQualifier = findQualifier(element, currentClass);
|
||||
//means java.lang.Object's method called from an interface
|
||||
if (actualQualifier == null) {
|
||||
actualQualifier = myCurrentEnclosingElement.peek();
|
||||
actualQualifier = currentClass;
|
||||
}
|
||||
collector.sinkReference(collector.asJavacRef(element, actualQualifier));
|
||||
collector.sinkReference(collector.asJavacRef(currentClass, element, actualQualifier));
|
||||
scan(node.getTypeArguments(), collector);
|
||||
scan(node.getArguments(), collector);
|
||||
return null;
|
||||
@@ -180,6 +180,10 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
return super.visitMethodInvocation(node, collector);
|
||||
}
|
||||
|
||||
protected TypeElement getCurrentEnclosingTypeElement() {
|
||||
return myCurrentEnclosingElement.empty()? null : myCurrentEnclosingElement.peek();
|
||||
}
|
||||
|
||||
private final Stack<TypeElement> myCurrentEnclosingElement = new Stack<TypeElement>(1);
|
||||
private final Stack<Long> myCurrentEnclosingElementOffset = new Stack<Long>(1);
|
||||
private final Stack<NewClassTree> myCurrentAnonymousTree = new Stack<NewClassTree>(1);
|
||||
@@ -199,7 +203,7 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
final JavacRef[] supers;
|
||||
if (superclass != refCollector.getTypeUtility().getNoType(TypeKind.NONE)) {
|
||||
supers = new JavacRef[interfaces.size() + 1];
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(superclass);
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), superclass);
|
||||
if (ref == null) return null;
|
||||
supers[interfaces.size()] = ref;
|
||||
}
|
||||
@@ -209,11 +213,11 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
|
||||
int i = 0;
|
||||
for (TypeMirror anInterface : interfaces) {
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(anInterface);
|
||||
final JavacRef.JavacElementRefBase ref = refCollector.asJavacRef(getCurrentEnclosingTypeElement(), anInterface);
|
||||
if (ref == null) return null;
|
||||
supers[i++] = ref;
|
||||
}
|
||||
final JavacRef.JavacElementRefBase aClass = refCollector.asJavacRef(element);
|
||||
final JavacRef.JavacElementRefBase aClass = refCollector.asJavacRef(null, element);
|
||||
if (aClass == null) return null;
|
||||
refCollector.sinkReference(aClass);
|
||||
refCollector.sinkDeclaration(new JavacDef.JavacClassDef(aClass, supers));
|
||||
@@ -234,12 +238,12 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
|
||||
|
||||
Element castType = collector.getReferencedElement(node.getType());
|
||||
if (castType == null) return null;
|
||||
JavacRef.JavacElementRefBase castTypeElement = collector.asJavacRef(castType);
|
||||
JavacRef.JavacElementRefBase castTypeElement = collector.asJavacRef(null, castType);
|
||||
if (!(castTypeElement instanceof JavacRef.JavacClass)) return null;
|
||||
|
||||
TypeMirror operandType = collector.getType(node.getExpression());
|
||||
if (operandType == null) return null;
|
||||
JavacRef.JavacElementRefBase operandTypeElement = collector.asJavacRef(operandType);
|
||||
JavacRef.JavacElementRefBase operandTypeElement = collector.asJavacRef(getCurrentEnclosingTypeElement(), operandType);
|
||||
if (!(operandTypeElement instanceof JavacRef.JavacClass)) return null;
|
||||
|
||||
collector.sinkTypeCast(new JavacTypeCast((JavacRef.JavacClass) operandTypeElement, (JavacRef.JavacClass) castTypeElement));
|
||||
|
||||
@@ -27,20 +27,17 @@ public class JavacFileData {
|
||||
|
||||
private final String myFilePath;
|
||||
private final TObjectIntHashMap<JavacRef> myRefs;
|
||||
private final TObjectIntHashMap<JavacRef> myImportRefs;
|
||||
private final List<JavacTypeCast> myCasts;
|
||||
private final List<JavacDef> myDefs;
|
||||
private final Set<JavacRef> myImplicitRefs;
|
||||
|
||||
public JavacFileData(@NotNull String path,
|
||||
@NotNull TObjectIntHashMap<JavacRef> refs,
|
||||
@NotNull TObjectIntHashMap<JavacRef> importRefs,
|
||||
@NotNull List<JavacTypeCast> casts,
|
||||
@NotNull List<JavacDef> defs,
|
||||
@NotNull Set<JavacRef> implicitRefs) {
|
||||
myFilePath = path;
|
||||
myRefs = refs;
|
||||
myImportRefs = importRefs;
|
||||
myCasts = casts;
|
||||
myDefs = defs;
|
||||
myImplicitRefs = implicitRefs;
|
||||
@@ -61,11 +58,6 @@ public class JavacFileData {
|
||||
return myRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TObjectIntHashMap<JavacRef> getImportRefs() {
|
||||
return myImportRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JavacTypeCast> getCasts() {
|
||||
return myCasts;
|
||||
@@ -83,7 +75,6 @@ public class JavacFileData {
|
||||
try {
|
||||
stream.writeUTF(getFilePath());
|
||||
saveRefs(stream, getRefs());
|
||||
saveRefs(stream, getImportRefs());
|
||||
saveCasts(stream, getCasts());
|
||||
saveDefs(stream, getDefs());
|
||||
saveImplicitToString(stream, getImplicitToStringRefs());
|
||||
@@ -99,12 +90,12 @@ public class JavacFileData {
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
try {
|
||||
return new JavacFileData(in.readUTF(),
|
||||
readRefs(in),
|
||||
readRefs(in),
|
||||
readCasts(in),
|
||||
readDefs(in),
|
||||
readImplicitToString(in));
|
||||
final String path = in.readUTF();
|
||||
final TObjectIntHashMap<JavacRef> refs = readRefs(in);
|
||||
final List<JavacTypeCast> casts = readCasts(in);
|
||||
final List<JavacDef> defs = readDefs(in);
|
||||
final Set<JavacRef> implicitRefs = readImplicitToString(in);
|
||||
return new JavacFileData(path, refs, casts, defs, implicitRefs);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -213,10 +204,13 @@ public class JavacFileData {
|
||||
}
|
||||
else if (ref instanceof JavacRef.JavacField) {
|
||||
out.writeByte(FIELD_MARKER);
|
||||
out.writeUTF(((JavacRef.JavacField)ref).getContainingClass());
|
||||
out.writeUTF(ref.getOwnerName());
|
||||
out.writeUTF(((JavacRef.JavacField)ref).getDescriptor());
|
||||
}
|
||||
else if (ref instanceof JavacRef.JavacMethod) {
|
||||
out.writeByte(METHOD_MARKER);
|
||||
out.writeUTF(((JavacRef.JavacMethod)ref).getContainingClass());
|
||||
out.writeUTF(ref.getOwnerName());
|
||||
out.write(((JavacRef.JavacMethod)ref).getParamCount());
|
||||
}
|
||||
@@ -231,11 +225,27 @@ public class JavacFileData {
|
||||
final byte marker = in.readByte();
|
||||
switch (marker) {
|
||||
case CLASS_MARKER:
|
||||
return new JavacRef.JavacClassImpl(in.readBoolean(), readModifiers(in), in.readUTF());
|
||||
final boolean isAnonymous = in.readBoolean();
|
||||
final Set<Modifier> classModifiers = readModifiers(in);
|
||||
final String className = in.readUTF();
|
||||
return new JavacRef.JavacClassImpl(isAnonymous, classModifiers, className);
|
||||
|
||||
case METHOD_MARKER:
|
||||
return new JavacRef.JavacMethodImpl(in.readUTF(), in.readByte(), readModifiers(in), in.readUTF());
|
||||
final String methodContainingClass = in.readUTF();
|
||||
final String methodOwnerName = in.readUTF();
|
||||
final byte methodParamCount = in.readByte();
|
||||
final Set<Modifier> methodModifiers = readModifiers(in);
|
||||
final String methodName = in.readUTF();
|
||||
return new JavacRef.JavacMethodImpl(methodContainingClass, methodOwnerName, methodParamCount, methodModifiers, methodName);
|
||||
|
||||
case FIELD_MARKER:
|
||||
return new JavacRef.JavacFieldImpl(in.readUTF(), readModifiers(in), in.readUTF());
|
||||
final String fieldContainingClass = in.readUTF();
|
||||
final String fieldOwnerName = in.readUTF();
|
||||
final String fieldDescriptor = in.readUTF();
|
||||
final Set<Modifier> fieldModifiers = readModifiers(in);
|
||||
final String fieldName = in.readUTF();
|
||||
return new JavacRef.JavacFieldImpl(fieldContainingClass, fieldOwnerName, fieldModifiers, fieldName, fieldDescriptor);
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("unknown marker " + marker);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||
import java.util.Set;
|
||||
|
||||
public interface JavacRef {
|
||||
@@ -61,13 +61,17 @@ public interface JavacRef {
|
||||
|
||||
interface JavacClass extends JavacRef {
|
||||
boolean isAnonymous();
|
||||
boolean isPackageInfo();
|
||||
}
|
||||
|
||||
interface JavacMethod extends JavacRef {
|
||||
byte getParamCount();
|
||||
String getContainingClass();
|
||||
}
|
||||
|
||||
interface JavacField extends JavacRef {
|
||||
String getDescriptor();
|
||||
String getContainingClass();
|
||||
}
|
||||
|
||||
abstract class JavacRefBase implements JavacRef {
|
||||
@@ -115,18 +119,31 @@ public interface JavacRef {
|
||||
public boolean isAnonymous() {
|
||||
return myAnonymous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPackageInfo() {
|
||||
final String name = getName();
|
||||
return name.endsWith(".package-info") || "package-info".equals(name);
|
||||
}
|
||||
}
|
||||
|
||||
class JavacMethodImpl extends JavacRefBase implements JavacMethod {
|
||||
private final String myContainingClassName;
|
||||
private final String myOwnerName;
|
||||
private final byte myParamCount;
|
||||
|
||||
public JavacMethodImpl(String ownerName, byte paramCount, Set<Modifier> modifiers, String name) {
|
||||
public JavacMethodImpl(String containingClassName, String ownerName, byte paramCount, Set<Modifier> modifiers, String name) {
|
||||
super(name, modifiers);
|
||||
myContainingClassName = containingClassName;
|
||||
myOwnerName = ownerName;
|
||||
myParamCount = paramCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingClass() {
|
||||
return myContainingClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getParamCount() {
|
||||
return myParamCount;
|
||||
@@ -140,11 +157,21 @@ public interface JavacRef {
|
||||
}
|
||||
|
||||
class JavacFieldImpl extends JavacRefBase implements JavacField {
|
||||
private final String myOwnerName;
|
||||
|
||||
public JavacFieldImpl(String ownerName, Set<Modifier> modifiers, String name) {
|
||||
private final String myContainingClassName;
|
||||
private final String myOwnerName;
|
||||
private final String myDescriptor;
|
||||
|
||||
public JavacFieldImpl(String containingClassName, String ownerName, Set<Modifier> modifiers, String name, String descriptor) {
|
||||
super(name, modifiers);
|
||||
myContainingClassName = containingClassName;
|
||||
myOwnerName = ownerName;
|
||||
myDescriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingClass() {
|
||||
return myContainingClassName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -152,6 +179,11 @@ public interface JavacRef {
|
||||
public String getOwnerName() {
|
||||
return myOwnerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
return myDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class JavacElementRefBase implements JavacRef {
|
||||
@@ -191,12 +223,12 @@ public interface JavacRef {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JavacElementRefBase fromElement(Element element, Element qualifier, JavacNameTable nameTableCache) {
|
||||
return fromElement(element, qualifier, nameTableCache, null);
|
||||
public static JavacElementRefBase fromElement(final String containingClass, Element element, Element qualifier, JavacNameTable nameTableCache) {
|
||||
return fromElement(containingClass, element, qualifier, nameTableCache, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JavacElementRefBase fromElement(Element element, Element qualifier, JavacNameTable nameTableCache, @Nullable ImportProperties importProps) {
|
||||
public static JavacElementRefBase fromElement(final String containigClass, Element element, Element qualifier, JavacNameTable nameTableCache, @Nullable ImportProperties importProps) {
|
||||
if (qualifier != null) {
|
||||
TypeMirror type = qualifier.asType();
|
||||
if (!isValidType(type)) {
|
||||
@@ -208,11 +240,11 @@ public interface JavacRef {
|
||||
}
|
||||
else if (element instanceof VariableElement) {
|
||||
if (qualifier == null && !checkEnclosingElement(element)) return null;
|
||||
return new JavacElementFieldImpl(element, qualifier, nameTableCache, importProps);
|
||||
return new JavacElementFieldImpl(containigClass, element, qualifier, nameTableCache, importProps);
|
||||
}
|
||||
else if (element instanceof ExecutableElement) {
|
||||
if (qualifier == null && !checkEnclosingElement(element)) return null;
|
||||
return new JavacElementMethodImpl(element, qualifier, nameTableCache, importProps);
|
||||
return new JavacElementMethodImpl(containigClass, element, qualifier, nameTableCache, importProps);
|
||||
}
|
||||
else if (element == null || element.getKind() == ElementKind.OTHER || element.getKind() == ElementKind.TYPE_PARAMETER) {
|
||||
// javac reserved symbol kind (e.g: com.sun.tools.javac.comp.Resolve.ResolveError)
|
||||
@@ -270,11 +302,24 @@ public interface JavacRef {
|
||||
public boolean isAnonymous() {
|
||||
return myNameTableCache.parseName(myOriginalElement.getSimpleName()).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPackageInfo() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class JavacElementMethodImpl extends JavacElementRefBase implements JavacMethod {
|
||||
public JavacElementMethodImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache, final ImportProperties importProps) {
|
||||
private final String myContainingClass;
|
||||
|
||||
public JavacElementMethodImpl(String containingClass, @NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache, final ImportProperties importProps) {
|
||||
super(element, qualifier, nameTableCache, importProps);
|
||||
myContainingClass = containingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingClass() {
|
||||
return myContainingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,8 +329,51 @@ public interface JavacRef {
|
||||
}
|
||||
|
||||
class JavacElementFieldImpl extends JavacElementRefBase implements JavacField {
|
||||
public JavacElementFieldImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache, final ImportProperties importProps) {
|
||||
private final String myContainingClass;
|
||||
|
||||
public JavacElementFieldImpl(String containingClass, @NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache, final ImportProperties importProps) {
|
||||
super(element, qualifier, nameTableCache, importProps);
|
||||
myContainingClass = containingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingClass() {
|
||||
return myContainingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
return calcDescriptor(myOriginalElement.asType());
|
||||
}
|
||||
|
||||
private String calcDescriptor(TypeMirror type) {
|
||||
return new SimpleTypeVisitor6<String, Void>(null) {
|
||||
@Override
|
||||
public String visitPrimitive(PrimitiveType t, Void aVoid) {
|
||||
switch(t.getKind()) {
|
||||
case BYTE: return "B";
|
||||
case CHAR: return "C";
|
||||
case DOUBLE: return "D";
|
||||
case FLOAT: return "F";
|
||||
case INT: return "I";
|
||||
case LONG:return "J";
|
||||
case SHORT: return "S";
|
||||
case BOOLEAN: return "Z";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitArray(ArrayType t, Void aVoid) {
|
||||
return "[" + visit(t.getComponentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitDeclared(DeclaredType t, Void aVoid) {
|
||||
return "L" + myNameTableCache.parseBinaryName(t.asElement()).replace('.', '/') + ";";
|
||||
}
|
||||
|
||||
}.visit(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,4 +14,4 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
org.jetbrains.jps.backwardRefs.JavaBackwardReferenceRegistrar
|
||||
org.jetbrains.jps.incremental.java.ImportReferencesRegistrar
|
||||
org.jetbrains.jps.incremental.java.JpsReferenceDependenciesRegistrar
|
||||
|
||||
+1
-5
@@ -23,12 +23,8 @@ public class JavaBackwardReferenceRegistrar implements JavacFileReferencesRegist
|
||||
return JavaBackwardReferenceIndexWriter.isEnabled() && JavaBackwardReferenceIndexWriter.getInstance() != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean onlyImports() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFile(CompileContext context, String filePath,
|
||||
TObjectIntHashMap<? extends JavacRef> refs,
|
||||
Collection<? extends JavacDef> defs,
|
||||
|
||||
@@ -27,10 +27,36 @@ import java.util.concurrent.Future;
|
||||
*/
|
||||
public class Callbacks {
|
||||
|
||||
public interface ConstantRef {
|
||||
String getOwner();
|
||||
String getName();
|
||||
String getDescriptor();
|
||||
}
|
||||
|
||||
public interface Backend {
|
||||
void associate(String classFileName, String sourceFileName, ClassReader cr);
|
||||
void associate(String classFileName, Collection<String> sources, ClassReader cr);
|
||||
void registerImports(String className, Collection<String> classImports, Collection<String> staticImports);
|
||||
void registerConstantReferences(String className, Collection<ConstantRef> cRefs);
|
||||
}
|
||||
|
||||
public static ConstantRef createConstantReference(String ownerClass, String fieldName, String descriptor) {
|
||||
return new ConstantRef() {
|
||||
@Override
|
||||
public String getOwner() {
|
||||
return ownerClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class ConstantAffection {
|
||||
|
||||
@@ -28,6 +28,7 @@ public class ClassRepr extends ClassFileRepr {
|
||||
private final int myOuterClassName;
|
||||
private final boolean myIsLocal;
|
||||
private final boolean myIsAnonymous;
|
||||
private boolean myHasInlinedConstants;
|
||||
|
||||
public Set<MethodRepr> getMethods() {
|
||||
return myMethods;
|
||||
@@ -49,6 +50,14 @@ public class ClassRepr extends ClassFileRepr {
|
||||
return myIsAnonymous;
|
||||
}
|
||||
|
||||
public boolean hasInlinedConstants() {
|
||||
return myHasInlinedConstants;
|
||||
}
|
||||
|
||||
public void setHasInlinedConstants(boolean hasConstants) {
|
||||
myHasInlinedConstants = hasConstants;
|
||||
}
|
||||
|
||||
public TypeRepr.ClassType getSuperClass() {
|
||||
return mySuperClass;
|
||||
}
|
||||
@@ -106,10 +115,13 @@ public class ClassRepr extends ClassFileRepr {
|
||||
if (!mySuperClass.equals(pastClass.mySuperClass)) {
|
||||
base |= Difference.SUPERCLASS;
|
||||
}
|
||||
|
||||
if (!getUsages().equals(pastClass.getUsages())) {
|
||||
base |= Difference.USAGES;
|
||||
}
|
||||
if (hasInlinedConstants() != pastClass.hasInlinedConstants()) {
|
||||
base |= Difference.CONSTANT_REFERENCES;
|
||||
}
|
||||
|
||||
final int d = base;
|
||||
|
||||
return new Diff(diff) {
|
||||
@@ -244,6 +256,7 @@ public class ClassRepr extends ClassFileRepr {
|
||||
int flags = DataInputOutputUtil.readINT(in);
|
||||
myIsLocal = (flags & LOCAL_MASK) != 0;
|
||||
myIsAnonymous = (flags & ANONYMOUS_MASK) != 0;
|
||||
myHasInlinedConstants = (flags & HAS_INLINED_CONSTANTS_MASK) != 0;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
@@ -252,6 +265,7 @@ public class ClassRepr extends ClassFileRepr {
|
||||
|
||||
private static final int LOCAL_MASK = 1;
|
||||
private static final int ANONYMOUS_MASK = 2;
|
||||
private static final int HAS_INLINED_CONSTANTS_MASK = 4;
|
||||
|
||||
@Override
|
||||
public void save(final DataOutput out) {
|
||||
@@ -264,7 +278,9 @@ public class ClassRepr extends ClassFileRepr {
|
||||
RW.save(myAnnotationTargets, UsageRepr.AnnotationUsage.elementTypeExternalizer, out);
|
||||
RW.writeUTF(out, myRetentionPolicy == null ? "" : myRetentionPolicy.toString());
|
||||
DataInputOutputUtil.writeINT(out, myOuterClassName);
|
||||
DataInputOutputUtil.writeINT(out, (myIsLocal ? LOCAL_MASK:0) | (myIsAnonymous ? ANONYMOUS_MASK : 0));
|
||||
DataInputOutputUtil.writeINT(
|
||||
out, (myIsLocal ? LOCAL_MASK:0) | (myIsAnonymous ? ANONYMOUS_MASK : 0) | (myHasInlinedConstants ? HAS_INLINED_CONSTANTS_MASK : 0)
|
||||
);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
@@ -380,6 +396,8 @@ public class ClassRepr extends ClassFileRepr {
|
||||
stream.println(myIsLocal);
|
||||
stream.print(" Anonymous class: ");
|
||||
stream.println(myIsAnonymous);
|
||||
stream.print(" Has inlined constants: ");
|
||||
stream.println(myHasInlinedConstants);
|
||||
|
||||
stream.println(" Fields:");
|
||||
final FieldRepr[] fs = myFields.toArray(new FieldRepr[0]);
|
||||
|
||||
@@ -29,6 +29,7 @@ public abstract class Difference {
|
||||
public static final int SUPERCLASS = 16;
|
||||
public static final int USAGES = 32;
|
||||
public static final int ANNOTATIONS = 64;
|
||||
public static final int CONSTANT_REFERENCES = 128;
|
||||
|
||||
public interface Specifier<T, D extends Difference> {
|
||||
Collection<T> added();
|
||||
|
||||
+96
-164
@@ -24,7 +24,6 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -33,6 +32,8 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public class Mappings {
|
||||
private final static Logger LOG = Logger.getInstance(Mappings.class);
|
||||
public static final String PROCESS_CONSTANTS_NON_INCREMENTAL_PROPERTY = "compiler.process.constants.non.incremental";
|
||||
private final boolean myProcessConstantsIncrementally = !Boolean.valueOf(System.getProperty(PROCESS_CONSTANTS_NON_INCREMENTAL_PROPERTY, "false"));
|
||||
|
||||
private final static String CLASS_TO_SUBCLASSES = "classToSubclasses.tab";
|
||||
private final static String CLASS_TO_CLASS = "classToClass.tab";
|
||||
@@ -1012,7 +1013,7 @@ public class Mappings {
|
||||
}
|
||||
|
||||
private class Differential {
|
||||
private static final int DESPERATE_MASK = Opcodes.ACC_FINAL;
|
||||
private static final int INLINABLE_FIELD_MODIFIERS_MASK = Opcodes.ACC_FINAL;
|
||||
|
||||
final Mappings myDelta;
|
||||
final Collection<? extends File> myFilesToCompile;
|
||||
@@ -1021,8 +1022,6 @@ public class Mappings {
|
||||
final Collection<? super File> myAffectedFiles;
|
||||
@Nullable
|
||||
final DependentFilesFilter myFilter;
|
||||
@Nullable final Callbacks.ConstantAffectionResolver myConstantSearch;
|
||||
final DelayedWorks myDelayedWorks;
|
||||
|
||||
final Util myFuture;
|
||||
final Util myPresent;
|
||||
@@ -1032,90 +1031,6 @@ public class Mappings {
|
||||
private final Iterable<AnnotationsChangeTracker> myAnnotationChangeTracker =
|
||||
JpsServiceManager.getInstance().getExtensions(AnnotationsChangeTracker.class);
|
||||
|
||||
private class DelayedWorks {
|
||||
class Triple {
|
||||
final int owner;
|
||||
final FieldRepr field;
|
||||
@Nullable
|
||||
final Future<? extends Callbacks.ConstantAffection> affection;
|
||||
|
||||
private Triple(final int owner, final FieldRepr field, @Nullable final Future<? extends Callbacks.ConstantAffection> affection) {
|
||||
this.owner = owner;
|
||||
this.field = field;
|
||||
this.affection = affection;
|
||||
}
|
||||
|
||||
Callbacks.ConstantAffection getAffection() {
|
||||
try {
|
||||
return affection != null ? affection.get() : Callbacks.ConstantAffection.EMPTY;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Collection<Triple> myQueue = new LinkedList<>();
|
||||
|
||||
void addConstantWork(final int ownerClass, final FieldRepr changedField, final boolean isRemoved, boolean accessChanged) {
|
||||
final Future<Callbacks.ConstantAffection> future;
|
||||
if (myConstantSearch == null) {
|
||||
future = null;
|
||||
}
|
||||
else {
|
||||
final String className = myContext.getValue(ownerClass);
|
||||
final String fieldName = myContext.getValue(changedField.name);
|
||||
future = myConstantSearch.request(className.replace('/', '.'), fieldName, changedField.access, isRemoved, accessChanged);
|
||||
}
|
||||
myQueue.add(new Triple(ownerClass, changedField, future));
|
||||
}
|
||||
|
||||
boolean doWork(@NotNull final Collection<? super File> affectedFiles) {
|
||||
if (!myQueue.isEmpty()) {
|
||||
debug("Starting delayed works.");
|
||||
|
||||
for (final Triple t : myQueue) {
|
||||
final Callbacks.ConstantAffection affection = t.getAffection();
|
||||
|
||||
debug("Class: ", t.owner);
|
||||
debug("Field: ", t.field.name);
|
||||
|
||||
if (!affection.isKnown()) {
|
||||
if (myConstantSearch != null) {
|
||||
debug("No external dependency information available.");
|
||||
}
|
||||
else {
|
||||
debug("Constant search service not available.");
|
||||
}
|
||||
debug("Trying to soften non-incremental decision.");
|
||||
if (!incrementalDecision(t.owner, t.field, affectedFiles, myFilesToCompile, myFilter)) {
|
||||
debug("No luck.");
|
||||
debug("End of delayed work, returning false.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug("External dependency information retrieved.");
|
||||
final Collection<File> files = affection.getAffectedFiles();
|
||||
if (myFilter == null) {
|
||||
affectedFiles.addAll(files);
|
||||
}
|
||||
else {
|
||||
for (File file : files) {
|
||||
if (myFilter.accept(file)) {
|
||||
affectedFiles.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("End of delayed work, returning true.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClasses {
|
||||
final File myFileName;
|
||||
final Set<ClassRepr> myFileClasses = new THashSet<>();
|
||||
@@ -1157,31 +1072,20 @@ public class Mappings {
|
||||
this.myCompiledWithErrors = null;
|
||||
this.myAffectedFiles = null;
|
||||
this.myFilter = null;
|
||||
this.myConstantSearch = null;
|
||||
|
||||
myDelayedWorks = null;
|
||||
|
||||
myFuture = null;
|
||||
myPresent = null;
|
||||
|
||||
myEasyMode = true;
|
||||
|
||||
delta.myIsRebuild = true;
|
||||
}
|
||||
|
||||
private Differential(final Mappings delta, final Collection<String> removed, final Collection<? extends File> filesToCompile) {
|
||||
delta.myRemovedFiles = removed;
|
||||
|
||||
this.myDelta = delta;
|
||||
this.myFilesToCompile = filesToCompile;
|
||||
this.myCompiledFiles = null;
|
||||
this.myCompiledWithErrors = null;
|
||||
this.myAffectedFiles = null;
|
||||
this.myFilter = null;
|
||||
this.myConstantSearch = null;
|
||||
|
||||
myDelayedWorks = null;
|
||||
|
||||
myFuture = new Util(delta);
|
||||
myPresent = new Util();
|
||||
myEasyMode = true;
|
||||
@@ -1193,8 +1097,7 @@ public class Mappings {
|
||||
final Collection<? extends File> compiledWithErrors,
|
||||
final Collection<? extends File> compiledFiles,
|
||||
final Collection<? super File> affectedFiles,
|
||||
@NotNull final DependentFilesFilter filter,
|
||||
@Nullable final Callbacks.ConstantAffectionResolver constantSearch) {
|
||||
@NotNull final DependentFilesFilter filter) {
|
||||
delta.myRemovedFiles = removed;
|
||||
|
||||
this.myDelta = delta;
|
||||
@@ -1203,9 +1106,6 @@ public class Mappings {
|
||||
this.myCompiledWithErrors = compiledWithErrors;
|
||||
this.myAffectedFiles = affectedFiles;
|
||||
this.myFilter = filter;
|
||||
this.myConstantSearch = constantSearch;
|
||||
|
||||
myDelayedWorks = new DelayedWorks();
|
||||
|
||||
myFuture = new Util(delta);
|
||||
myPresent = new Util();
|
||||
@@ -1755,17 +1655,11 @@ public class Mappings {
|
||||
for (final FieldRepr f : removed) {
|
||||
debug("Field: ", f.name);
|
||||
|
||||
if (!f.isPrivate() && (f.access & DESPERATE_MASK) == DESPERATE_MASK && f.hasValue()) {
|
||||
if (!myProcessConstantsIncrementally && !f.isPrivate() && (f.access & INLINABLE_FIELD_MODIFIERS_MASK) == INLINABLE_FIELD_MODIFIERS_MASK && f.hasValue()) {
|
||||
debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested");
|
||||
if (myConstantSearch != null) {
|
||||
assert myDelayedWorks != null;
|
||||
myDelayedWorks.addConstantWork(it.name, f, true, false);
|
||||
}
|
||||
else {
|
||||
if (!incrementalDecision(it.name, f, myAffectedFiles, myFilesToCompile, myFilter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
}
|
||||
if (!incrementalDecision(it.name, f, myAffectedFiles, myFilesToCompile, myFilter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1788,6 +1682,7 @@ public class Mappings {
|
||||
}
|
||||
debug("Processing changed fields:");
|
||||
assert myFuture != null;
|
||||
assert myPresent != null;
|
||||
|
||||
for (final Pair<FieldRepr, Difference> f : changed) {
|
||||
final Difference d = f.second;
|
||||
@@ -1795,8 +1690,10 @@ public class Mappings {
|
||||
|
||||
debug("Field: ", field.name);
|
||||
|
||||
final Supplier<TIntHashSet> propagated = lazy(()-> myFuture.propagateFieldAccess(field.name, it.name));
|
||||
|
||||
// only if the field was a compile-time constant
|
||||
if (!field.isPrivate() && (field.access & DESPERATE_MASK) == DESPERATE_MASK && d.hadValue()) {
|
||||
if (!field.isPrivate() && (field.access & INLINABLE_FIELD_MODIFIERS_MASK) == INLINABLE_FIELD_MODIFIERS_MASK && d.hadValue()) {
|
||||
final int changedModifiers = d.addedModifiers() | d.removedModifiers();
|
||||
final boolean harmful = (changedModifiers & (Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) != 0;
|
||||
final boolean accessChanged = (changedModifiers & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) != 0;
|
||||
@@ -1804,12 +1701,12 @@ public class Mappings {
|
||||
final boolean valueChanged = (d.base() & Difference.VALUE) != 0;
|
||||
|
||||
if (harmful || valueChanged || becameLessAccessible) {
|
||||
debug("Inline field changed it's access or value => a switch to non-incremental mode requested");
|
||||
if (myConstantSearch != null) {
|
||||
assert myDelayedWorks != null;
|
||||
myDelayedWorks.addConstantWork(it.name, field, false, accessChanged);
|
||||
if (myProcessConstantsIncrementally) {
|
||||
debug("Potentially inlined field changed it's access or value => affecting field usages");
|
||||
myFuture.affectFieldUsages(field, propagated.get(), field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
|
||||
}
|
||||
else {
|
||||
debug("Potentially inlined field changed it's access or value => a switch to non-incremental mode requested");
|
||||
if (!incrementalDecision(it.name, field, myAffectedFiles, myFilesToCompile, myFilter)) {
|
||||
debug("End of Differentiate, returning false");
|
||||
return false;
|
||||
@@ -1819,7 +1716,6 @@ public class Mappings {
|
||||
}
|
||||
|
||||
if (d.base() != Difference.NONE) {
|
||||
final Supplier<TIntHashSet> propagated = lazy(()-> myFuture.propagateFieldAccess(field.name, it.name));
|
||||
|
||||
if ((d.base() & Difference.TYPE) != 0 || (d.base() & Difference.SIGNATURE) != 0) {
|
||||
debug("Type or signature changed --- affecting field usages");
|
||||
@@ -2289,7 +2185,7 @@ public class Mappings {
|
||||
}
|
||||
|
||||
private void processDependentFile(int depClass, @NotNull File depFile) {
|
||||
if (myAffectedFiles.contains(depFile) || myCompiledFiles.contains(depFile)) {
|
||||
if (myAffectedFiles.contains(depFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2299,7 +2195,12 @@ public class Mappings {
|
||||
if (repr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (repr instanceof ClassRepr && !((ClassRepr)repr).hasInlinedConstants() && myCompiledFiles.contains(depFile)) {
|
||||
// Classes containing inlined constants from other classes and compiled against older constant values
|
||||
// may need to be recompiled several times within a compile session.
|
||||
// Otherwise it is safe to skip the file if it has already been compiled in this session.
|
||||
return;
|
||||
}
|
||||
final Set<UsageRepr.Usage> depUsages = repr.getUsages();
|
||||
if (depUsages == null || depUsages.isEmpty()) {
|
||||
return;
|
||||
@@ -2432,7 +2333,7 @@ public class Mappings {
|
||||
return false;
|
||||
}
|
||||
assert myAffectedFiles != null;
|
||||
assert myDelayedWorks != null;
|
||||
//assert myDelayedWorks != null;
|
||||
|
||||
final Collection<String> removed = myDelta.myRemovedFiles;
|
||||
if (removed != null) {
|
||||
@@ -2440,7 +2341,7 @@ public class Mappings {
|
||||
myAffectedFiles.remove(new File(r));
|
||||
}
|
||||
}
|
||||
return myDelayedWorks.doWork(myAffectedFiles);
|
||||
return true/*myDelayedWorks.doWork(myAffectedFiles)*/;
|
||||
}
|
||||
finally {
|
||||
if (myFilesToCompile != null) {
|
||||
@@ -2587,7 +2488,7 @@ public class Mappings {
|
||||
final Collection<? super File> affectedFiles,
|
||||
@NotNull final DependentFilesFilter filter,
|
||||
@Nullable final Callbacks.ConstantAffectionResolver constantSearch) {
|
||||
return new Differential(delta, removed, filesToCompile, compiledWithErrors, compiledFiles, affectedFiles, filter, constantSearch).differentiate();
|
||||
return new Differential(delta, removed, filesToCompile, compiledWithErrors, compiledFiles, affectedFiles, filter).differentiate();
|
||||
}
|
||||
|
||||
private void cleanupBackDependency(final int className, @Nullable Set<? extends UsageRepr.Usage> usages, final IntIntMultiMaplet buffer) {
|
||||
@@ -2854,6 +2755,9 @@ public class Mappings {
|
||||
|
||||
public Callbacks.Backend getCallback() {
|
||||
return new Callbacks.Backend() {
|
||||
// className -> {imports; static_imports}
|
||||
private final Map<String, Pair<Collection<String>, Collection<String>>> myImportRefs = Collections.synchronizedMap(new HashMap<>());
|
||||
private final Map<String, Collection<Callbacks.ConstantRef>> myConstantRefs = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
@Override
|
||||
public void associate(String classFileName, Collection<String> sources, ClassReader cr) {
|
||||
@@ -2864,6 +2768,20 @@ public class Mappings {
|
||||
// since java9 'repr' can represent either a class or a compiled module-info.java
|
||||
final int className = result.name;
|
||||
|
||||
if (result instanceof ClassRepr) {
|
||||
final ClassRepr classRepr = (ClassRepr)result;
|
||||
final String classNameStr = myContext.getValue(className);
|
||||
if (addConstantUsages(classRepr, myConstantRefs.remove(classNameStr))) {
|
||||
// Important: should register constants before imports, because imports can produce additional
|
||||
// field references too and addConstantUsages may return false in this case
|
||||
classRepr.setHasInlinedConstants(true);
|
||||
}
|
||||
final Pair<Collection<String>, Collection<String>> imports = myImportRefs.remove(classNameStr);
|
||||
if (imports != null) {
|
||||
addImportUsages(classRepr, imports.getFirst(), imports.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
for (String sourceFileName : sources) {
|
||||
String relative = myRelativizer.toRelative(sourceFileName);
|
||||
myClassToRelativeSourceFilePath.put(className, relative);
|
||||
@@ -2893,47 +2811,61 @@ public class Mappings {
|
||||
|
||||
@Override
|
||||
public void registerImports(String className, Collection<String> classImports, Collection<String> staticImports) {
|
||||
final String key = className.replace('.', '/');
|
||||
if (!classImports.isEmpty() || !staticImports.isEmpty()) {
|
||||
myPostPasses.offer(() -> {
|
||||
final int rootClassName = myContext.get(className.replace(".", "/"));
|
||||
final Collection<File> files = classToSourceFileGet(rootClassName);
|
||||
final ClassRepr repr = files != null && !files.isEmpty()? getClassReprByName(files.iterator().next(), rootClassName) : null;
|
||||
boolean usageAdded = false;
|
||||
|
||||
for (final String anImport : classImports) {
|
||||
if (!anImport.endsWith(IMPORT_WILDCARD_SUFFIX)) {
|
||||
final int iname = myContext.get(anImport.replace('.', '/'));
|
||||
myClassToClassDependency.put(iname, rootClassName);
|
||||
usageAdded |= repr != null && repr.addUsage(UsageRepr.createClassUsage(myContext, iname));
|
||||
}
|
||||
}
|
||||
|
||||
for (String anImport : staticImports) {
|
||||
if (anImport.endsWith(IMPORT_WILDCARD_SUFFIX)) {
|
||||
final int iname = myContext.get(anImport.substring(0, anImport.length() - IMPORT_WILDCARD_SUFFIX.length()).replace('.', '/'));
|
||||
myClassToClassDependency.put(iname, rootClassName);
|
||||
usageAdded |= repr != null && repr.addUsage(UsageRepr.createClassUsage(myContext, iname));
|
||||
usageAdded |= repr != null && repr.addUsage(UsageRepr.createImportStaticOnDemandUsage(myContext, iname));
|
||||
}
|
||||
else {
|
||||
final int i = anImport.lastIndexOf('.');
|
||||
if (i > 0 && i < anImport.length() - 1) {
|
||||
final int iname = myContext.get(anImport.substring(0, i).replace('.', '/'));
|
||||
final int memberName = myContext.get(anImport.substring(i+1));
|
||||
myClassToClassDependency.put(iname, rootClassName);
|
||||
usageAdded |= repr != null && repr.addUsage(UsageRepr.createClassUsage(myContext, iname));
|
||||
usageAdded |= repr != null && repr.addUsage(UsageRepr.createImportStaticMemberUsage(myContext, memberName, iname));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usageAdded) {
|
||||
for (File file : files) {
|
||||
myRelativeSourceFilePathToClasses.put(toRelative(file), repr);
|
||||
}
|
||||
}
|
||||
});
|
||||
myImportRefs.put(key, Pair.create(classImports, staticImports));
|
||||
}
|
||||
else {
|
||||
myImportRefs.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerConstantReferences(String className, Collection<Callbacks.ConstantRef> cRefs) {
|
||||
final String key = className.replace('.', '/');
|
||||
if (!cRefs.isEmpty()) {
|
||||
myConstantRefs.put(key, cRefs);
|
||||
}
|
||||
else {
|
||||
myConstantRefs.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void addImportUsages(ClassRepr repr, Collection<String> classImports, Collection<String> staticImports) {
|
||||
for (final String anImport : classImports) {
|
||||
if (!anImport.endsWith(IMPORT_WILDCARD_SUFFIX)) {
|
||||
repr.addUsage(UsageRepr.createClassUsage(myContext, myContext.get(anImport.replace('.', '/'))));
|
||||
}
|
||||
}
|
||||
for (String anImport : staticImports) {
|
||||
if (anImport.endsWith(IMPORT_WILDCARD_SUFFIX)) {
|
||||
final int iname = myContext.get(anImport.substring(0, anImport.length() - IMPORT_WILDCARD_SUFFIX.length()).replace('.', '/'));
|
||||
repr.addUsage(UsageRepr.createClassUsage(myContext, iname));
|
||||
repr.addUsage(UsageRepr.createImportStaticOnDemandUsage(myContext, iname));
|
||||
}
|
||||
else {
|
||||
final int i = anImport.lastIndexOf('.');
|
||||
if (i > 0 && i < anImport.length() - 1) {
|
||||
final int iname = myContext.get(anImport.substring(0, i).replace('.', '/'));
|
||||
final int memberName = myContext.get(anImport.substring(i+1));
|
||||
repr.addUsage(UsageRepr.createClassUsage(myContext, iname));
|
||||
repr.addUsage(UsageRepr.createImportStaticMemberUsage(myContext, memberName, iname));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addConstantUsages(ClassRepr repr, Collection<Callbacks.ConstantRef> cRefs) {
|
||||
boolean addedNewUsages = false;
|
||||
if (cRefs != null) {
|
||||
for (Callbacks.ConstantRef ref : cRefs) {
|
||||
final int owner = myContext.get(ref.getOwner().replace('.', '/'));
|
||||
if (repr.name != owner) {
|
||||
addedNewUsages |= repr.addUsage(UsageRepr.createFieldUsage(myContext, myContext.get(ref.getName()), owner, myContext.get(ref.getDescriptor())));
|
||||
}
|
||||
}
|
||||
}
|
||||
return addedNewUsages;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
private volatile long myLastEventOrdinal;
|
||||
private volatile ProjectDescriptor myProjectDescriptor;
|
||||
private final Map<Pair<String, String>, ConstantSearchFuture> mySearchTasks = Collections.synchronizedMap(new HashMap<>());
|
||||
private final ConstantSearch myConstantSearch = new ConstantSearch();
|
||||
private final ConstantSearch myConstantSearch = null/*new ConstantSearch()*/;
|
||||
@NotNull
|
||||
private final BuildRunner myBuildRunner;
|
||||
private final boolean myForceModelLoading;
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacDef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ImportReferencesRegistrar implements JavacFileReferencesRegistrar {
|
||||
@Override
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onlyImports() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFile(CompileContext context,
|
||||
String filePath,
|
||||
TObjectIntHashMap<? extends JavacRef> refs,
|
||||
Collection<? extends JavacDef> defs,
|
||||
Collection<? extends JavacTypeCast> casts,
|
||||
Collection<? extends JavacRef> implicitToString) {
|
||||
if (refs.isEmpty() || defs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final Set<String> classImports = new HashSet<>();
|
||||
final Set<String> staticImports = new HashSet<>();
|
||||
for (Object key : refs.keys()) {
|
||||
final JavacRef ref = (JavacRef)key;
|
||||
if (ref instanceof JavacRef.JavacClass) {
|
||||
classImports.add(ref.getName());
|
||||
final JavacRef.ImportProperties props = ref.getImportProperties();
|
||||
if (props != null && props.isStatic() && props.isOnDemand()) {
|
||||
staticImports.add(ref.getName() + ".*");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ref instanceof JavacRef.JavacField || ref instanceof JavacRef.JavacMethod) {
|
||||
staticImports.add(ref.getOwnerName() + "." + ref.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<String> definedClasses = new ArrayList<>();
|
||||
for (JavacDef def : defs) {
|
||||
if (def instanceof JavacDef.JavacClassDef) {
|
||||
final JavacRef element = def.getDefinedElement();
|
||||
if (element instanceof JavacRef.JavacClass) {
|
||||
definedClasses.add(element.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!definedClasses.isEmpty() && (!classImports.isEmpty() || !staticImports.isEmpty())) {
|
||||
final Callbacks.Backend deps = JavaBuilderUtil.getDependenciesRegistrar(context);
|
||||
for (String aClass : definedClasses) {
|
||||
deps.registerImports(aClass, classImports, staticImports);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1139,7 +1139,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
@Override
|
||||
public void registerJavacFileData(JavacFileData data) {
|
||||
for (JavacFileReferencesRegistrar registrar : myRegistrars) {
|
||||
registrar.registerFile(myContext, data.getFilePath(), registrar.onlyImports() ? data.getImportRefs() : data.getRefs(), data.getDefs(), data.getCasts(), data.getImplicitToStringRefs());
|
||||
registrar.registerFile(myContext, data.getFilePath(), data.getRefs(), data.getDefs(), data.getCasts(), data.getImplicitToStringRefs());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.jps.builders.java.JavaBuilderUtil;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.Callbacks;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacDef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacRef;
|
||||
import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* register dependencies that are not discoverable from bytecode:
|
||||
* - references caused by import statements
|
||||
* - references to fields initialized with compile-time constant values. Such values can be inlined into referencing bytecode
|
||||
*/
|
||||
public class JpsReferenceDependenciesRegistrar implements JavacFileReferencesRegistrar {
|
||||
@Override
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFile(CompileContext context,
|
||||
String filePath,
|
||||
TObjectIntHashMap<? extends JavacRef> refs,
|
||||
Collection<? extends JavacDef> defs,
|
||||
Collection<? extends JavacTypeCast> casts,
|
||||
Collection<? extends JavacRef> implicitToString) {
|
||||
final Set<String> definedClasses = new HashSet<>();
|
||||
for (JavacDef def : defs) {
|
||||
if (def instanceof JavacDef.JavacClassDef) {
|
||||
final JavacRef element = def.getDefinedElement();
|
||||
if (element instanceof JavacRef.JavacClass) {
|
||||
definedClasses.add(element.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (definedClasses.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!refs.isEmpty()) {
|
||||
final Set<String> classImports = new HashSet<>();
|
||||
final Set<String> staticImports = new HashSet<>();
|
||||
final Map<String, List<Callbacks.ConstantRef>> cRefs = new HashMap<>();
|
||||
refs.forEachKey(ref -> {
|
||||
final JavacRef.ImportProperties importProps = ref.getImportProperties();
|
||||
if (importProps != null) { // the reference comes from import list
|
||||
if (ref instanceof JavacRef.JavacClass) {
|
||||
classImports.add(ref.getName());
|
||||
if (importProps.isStatic() && importProps.isOnDemand()) {
|
||||
staticImports.add(ref.getName() + ".*");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ref instanceof JavacRef.JavacField || ref instanceof JavacRef.JavacMethod) {
|
||||
staticImports.add(ref.getOwnerName() + "." + ref.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ref instanceof JavacRef.JavacField && ref.getModifiers().contains(Modifier.FINAL)) {
|
||||
final JavacRef.JavacField fieldRef = (JavacRef.JavacField)ref;
|
||||
final String descriptor = fieldRef.getDescriptor();
|
||||
if (descriptor != null && definedClasses.contains(fieldRef.getContainingClass()) && !definedClasses.contains(fieldRef.getOwnerName())) {
|
||||
List<Callbacks.ConstantRef> refsList = cRefs.get(fieldRef.getContainingClass());
|
||||
if (refsList == null) {
|
||||
refsList = new ArrayList<>();
|
||||
cRefs.put(fieldRef.getContainingClass(), refsList);
|
||||
}
|
||||
refsList.add(Callbacks.createConstantReference(fieldRef.getOwnerName(), fieldRef.getName(), descriptor));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!classImports.isEmpty() || !staticImports.isEmpty()) {
|
||||
final Callbacks.Backend reg = JavaBuilderUtil.getDependenciesRegistrar(context);
|
||||
for (String aClass : definedClasses) {
|
||||
reg.registerImports(aClass, classImports, staticImports);
|
||||
}
|
||||
}
|
||||
if (!cRefs.isEmpty()) {
|
||||
final Callbacks.Backend reg = JavaBuilderUtil.getDependenciesRegistrar(context);
|
||||
for (String aClass : definedClasses) {
|
||||
final List<Callbacks.ConstantRef> classCRefs = cRefs.get(aClass);
|
||||
reg.registerConstantReferences(aClass, classCRefs != null? classCRefs : Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-11
@@ -28,15 +28,4 @@ public class InProcessRefCollectorCompilerToolExtension extends AbstractRefColle
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean divideImportsRefs() {
|
||||
if (hasServiceManager()) {
|
||||
for (JavacFileReferencesRegistrar registrar : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) {
|
||||
if (registrar.isEnabled() && registrar.onlyImports()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-35
@@ -22,52 +22,25 @@ import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar;
|
||||
import org.jetbrains.jps.model.java.compiler.JavaCompilers;
|
||||
import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
public class ReferenceCollectorExternalJavacOptionsProvider implements ExternalJavacOptionsProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<String> getOptions(@NotNull JavaCompilingTool tool) {
|
||||
List<String> options = new ArrayList<>(2);
|
||||
if (tool.getId().equals(JavaCompilers.JAVAC_ID)) {
|
||||
final JavacReferenceCollectorOptions
|
||||
javacReferenceCollectorOptions = new JavacReferenceCollectorOptions();
|
||||
options.add("-D" + ExternalRefCollectorCompilerToolExtension.ENABLED_PARAM + "=" + javacReferenceCollectorOptions.isEnabled());
|
||||
if (javacReferenceCollectorOptions.isEnabled() && javacReferenceCollectorOptions.isImportRefsDivided()) {
|
||||
options.add("-D" + ExternalRefCollectorCompilerToolExtension.DIVIDE_IMPORTS_PARAM + "=true");
|
||||
}
|
||||
return Collections.singletonList("-D" + ExternalRefCollectorCompilerToolExtension.ENABLED_PARAM + "=" + isEnabled());
|
||||
}
|
||||
return options;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static class JavacReferenceCollectorOptions {
|
||||
private final boolean myEnabled;
|
||||
private final boolean myDivideImportRefs;
|
||||
|
||||
private JavacReferenceCollectorOptions() {
|
||||
boolean enabled = false;
|
||||
boolean divideImportRefs = false;
|
||||
for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) {
|
||||
if (listener.isEnabled()) {
|
||||
enabled = true;
|
||||
if (listener.onlyImports()) {
|
||||
divideImportRefs = true;
|
||||
}
|
||||
}
|
||||
private static boolean isEnabled() {
|
||||
for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) {
|
||||
if (listener.isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
myEnabled = enabled;
|
||||
myDivideImportRefs = divideImportRefs;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return myEnabled;
|
||||
}
|
||||
|
||||
public boolean isImportRefsDivided() {
|
||||
return myDivideImportRefs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ public interface JavacFileReferencesRegistrar {
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
boolean onlyImports();
|
||||
|
||||
void registerFile(CompileContext context,
|
||||
String filePath,
|
||||
TObjectIntHashMap<? extends JavacRef> refs,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.ether;
|
||||
|
||||
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
|
||||
import org.jetbrains.jps.incremental.storage.ProjectStamps;
|
||||
import org.jetbrains.jps.model.JpsDummyElement;
|
||||
import org.jetbrains.jps.model.JpsModuleRootModificationUtil;
|
||||
@@ -174,8 +175,8 @@ public class CommonTest extends IncrementalTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIntegrateOnNonIncrementalMake() {
|
||||
doTest();
|
||||
public void testIntegrateOnNonIncrementalMake() throws Exception {
|
||||
executeWithSystemProperty(Mappings.PROCESS_CONSTANTS_NON_INCREMENTAL_PROPERTY, String.valueOf(true), () -> doTest());
|
||||
}
|
||||
|
||||
public void testNothingChanged() {
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.jps.util.JpsPathUtil;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* @author db
|
||||
@@ -134,6 +135,22 @@ public abstract class IncrementalTestCase extends JpsBuildTestCase {
|
||||
return new File(workDir, StringUtil.trimEnd(path, suffix));
|
||||
}
|
||||
|
||||
public <T> T executeWithSystemProperty(String propName, String propValue, Callable<T> action) throws Exception {
|
||||
final String oldValue = System.getProperty(propName);
|
||||
try {
|
||||
System.setProperty(propName, propValue);
|
||||
return action.call();
|
||||
}
|
||||
finally {
|
||||
if (oldValue != null) {
|
||||
System.setProperty(propName, oldValue);
|
||||
}
|
||||
else {
|
||||
System.clearProperty(propName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BuildResult doTest() {
|
||||
setupInitialProject();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.jetbrains.ether;
|
||||
|
||||
import org.jetbrains.jps.builders.CompileScopeTestBuilder;
|
||||
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
|
||||
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
|
||||
import org.jetbrains.jps.model.JpsDummyElement;
|
||||
import org.jetbrains.jps.model.JpsModuleRootModificationUtil;
|
||||
import org.jetbrains.jps.model.java.JpsJavaDependencyScope;
|
||||
@@ -97,7 +98,7 @@ public class MarkDirtyTest extends IncrementalTestCase {
|
||||
doTestBuild(1).assertSuccessful();
|
||||
}
|
||||
|
||||
public void testTransitiveRecompile() {
|
||||
public void testTransitiveRecompile() throws Exception {
|
||||
JpsModule module = addModule();
|
||||
addTestRoot(module, "testSrc");
|
||||
JpsModule util = addModule("util", "util/src");
|
||||
@@ -106,7 +107,7 @@ public class MarkDirtyTest extends IncrementalTestCase {
|
||||
JpsModule lib = addModule("lib", "lib/src");
|
||||
addTestRoot(lib, "lib/testSrc");
|
||||
JpsModuleRootModificationUtil.addDependency(util, lib);
|
||||
doTestBuild(1).assertSuccessful();
|
||||
executeWithSystemProperty(Mappings.PROCESS_CONSTANTS_NON_INCREMENTAL_PROPERTY, String.valueOf(true), () -> doTestBuild(1)).assertSuccessful();
|
||||
}
|
||||
|
||||
public void testRecompileTwinDependencies() {
|
||||
|
||||
Reference in New Issue
Block a user