Skip to content

Commit 8c95c70

Browse files
Replace shared-tree compiler bindings with lazy semantic values
1 parent f1c84b3 commit 8c95c70

41 files changed

Lines changed: 984 additions & 649 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎java-checks/src/test/java/org/sonar/java/checks/DeadStoreCheckTest.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.junit.jupiter.api.Test;
2020
import org.sonar.java.checks.verifier.CheckVerifier;
2121
import org.sonar.java.checks.verifier.TestUtils;
22+
import org.sonar.java.model.SemanticValues;
2223
import org.sonar.java.model.declaration.VariableTreeImpl;
2324
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
2425
import org.sonar.plugins.java.api.tree.VariableTree;
@@ -64,7 +65,7 @@ private static class EraseSymbols extends BaseTreeVisitor {
6465
@Override
6566
public void visitVariable(VariableTree tree) {
6667
if (tree instanceof VariableTreeImpl varImpl) {
67-
varImpl.variableBinding = null;
68+
varImpl.variableSymbol = SemanticValues.UNKNOWN_SYMBOL;
6869
}
6970
super.visitVariable(tree);
7071
}

‎java-frontend/src/main/java/org/sonar/java/ast/JavaAstScanner.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public void simpleScan(InputFile inputFile, JParserConfig.Result result, Consume
166166
modifyCompilationUnit.accept(ast);
167167
visitor.visitFile(ast, sonarComponents != null && sonarComponents.fileCanBeSkipped(inputFile));
168168
String path = inputFile.toString();
169-
Set<JProblem> undefinedTypes = ast.sema.undefinedTypes();
169+
Set<JProblem> undefinedTypes = ast.undefinedTypes();
170170
collectUndefinedTypes(path, undefinedTypes);
171171
cleanUp.accept(ast);
172172
telemetryAnalysisKeys = javaAnalysisKeys.success();

‎java-frontend/src/main/java/org/sonar/java/model/AbstractTypedTree.java‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,18 @@
1616
*/
1717
package org.sonar.java.model;
1818

19-
import org.eclipse.jdt.core.dom.ITypeBinding;
19+
import java.util.function.Supplier;
2020
import org.sonar.plugins.java.api.semantic.Type;
2121

22-
import javax.annotation.Nullable;
23-
2422
/**
2523
* This class is intended for internal use during semantic analysis and should not be used in checks.
2624
*/
2725
public abstract class AbstractTypedTree extends JavaTree {
2826

29-
@Nullable
30-
public ITypeBinding typeBinding;
27+
public Supplier<Type> type = SemanticValues.UNKNOWN_TYPE;
3128

3229
public Type symbolType() {
33-
return typeBinding != null
34-
? root.sema.type(typeBinding)
35-
: Type.UNKNOWN;
30+
return type.get();
3631
}
3732

3833
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* SonarQube Java
3+
* Copyright (C) SonarSource Sàrl
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* You can redistribute and/or modify this program under the terms of
7+
* the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the Sonar Source-Available License for more details.
13+
*
14+
* You should have received a copy of the Sonar Source-Available License
15+
* along with this program; if not, see https://sonarsource.com/license/ssal/
16+
*/
17+
package org.sonar.java.model;
18+
19+
import java.util.Objects;
20+
import java.util.function.Function;
21+
import java.util.function.Supplier;
22+
import javax.annotation.Nullable;
23+
import org.eclipse.jdt.core.dom.IBinding;
24+
25+
final class EcjSemanticAttachment<B extends IBinding, T> implements Supplier<T> {
26+
27+
final B binding;
28+
private final Function<B, T> factory;
29+
private T value;
30+
31+
EcjSemanticAttachment(B binding, Function<B, T> factory) {
32+
this.binding = binding;
33+
this.factory = factory;
34+
}
35+
36+
@Override
37+
public T get() {
38+
if (value == null) {
39+
value = Objects.requireNonNull(factory.apply(binding));
40+
}
41+
return value;
42+
}
43+
44+
@Nullable
45+
static IBinding getBinding(Supplier<?> attachment) {
46+
return attachment instanceof EcjSemanticAttachment<?, ?> ecj ? ecj.binding : null;
47+
}
48+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* SonarQube Java
3+
* Copyright (C) SonarSource Sàrl
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* You can redistribute and/or modify this program under the terms of
7+
* the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the Sonar Source-Available License for more details.
13+
*
14+
* You should have received a copy of the Sonar Source-Available License
15+
* along with this program; if not, see https://sonarsource.com/license/ssal/
16+
*/
17+
package org.sonar.java.model;
18+
19+
import java.util.function.Supplier;
20+
import javax.annotation.Nullable;
21+
import org.eclipse.jdt.core.dom.IBinding;
22+
import org.eclipse.jdt.core.dom.IMethodBinding;
23+
import org.eclipse.jdt.core.dom.ITypeBinding;
24+
import org.eclipse.jdt.core.dom.IVariableBinding;
25+
import org.sonar.java.model.declaration.ClassTreeImpl;
26+
import org.sonar.java.model.declaration.MethodTreeImpl;
27+
import org.sonar.java.model.declaration.VariableTreeImpl;
28+
import org.sonar.java.model.expression.IdentifierTreeImpl;
29+
import org.sonar.java.model.expression.LambdaExpressionTreeImpl;
30+
import org.sonar.java.model.expression.MethodInvocationTreeImpl;
31+
import org.sonar.java.model.pattern.AbstractPatternTree;
32+
33+
final class EcjTreeBindings {
34+
35+
private EcjTreeBindings() {
36+
}
37+
38+
@Nullable
39+
static ITypeBinding typeBinding(Object tree) {
40+
return switch (tree) {
41+
case AbstractTypedTree t -> (ITypeBinding) EcjSemanticAttachment.getBinding(t.type);
42+
case ClassTreeImpl t -> (ITypeBinding) EcjSemanticAttachment.getBinding(t.typeSymbol);
43+
case TypeParameterTreeImpl t -> (ITypeBinding) EcjSemanticAttachment.getBinding(t.typeSymbol);
44+
case AbstractPatternTree t -> (ITypeBinding) EcjSemanticAttachment.getBinding(t.type);
45+
default -> throw new IllegalArgumentException("No ECJ type attachment: " + tree.getClass());
46+
};
47+
}
48+
49+
@Nullable
50+
static IMethodBinding methodBinding(Object tree) {
51+
Supplier<?> attachment = switch (tree) {
52+
case MethodTreeImpl t -> t.methodSymbol;
53+
case MethodInvocationTreeImpl t -> t.methodSymbolSupplier;
54+
case LambdaExpressionTreeImpl t -> t.methodSymbol;
55+
default -> throw new IllegalArgumentException("No ECJ method attachment: " + tree.getClass());
56+
};
57+
return (IMethodBinding) EcjSemanticAttachment.getBinding(attachment);
58+
}
59+
60+
@Nullable
61+
static IVariableBinding variableBinding(VariableTreeImpl tree) {
62+
return (IVariableBinding) EcjSemanticAttachment.getBinding(tree.variableSymbol);
63+
}
64+
65+
@Nullable
66+
static IBinding binding(Object tree) {
67+
return switch (tree) {
68+
case IdentifierTreeImpl t -> EcjSemanticAttachment.getBinding(t.symbolSupplier);
69+
case JavaTree.ImportTreeImpl t -> EcjSemanticAttachment.getBinding(t.symbolSupplier);
70+
default -> throw new IllegalArgumentException("No ECJ symbol attachment: " + tree.getClass());
71+
};
72+
}
73+
74+
static void setType(JSema sema, JavaTree tree, @Nullable ITypeBinding binding) {
75+
switch (tree) {
76+
case AbstractTypedTree t -> t.type = sema.typeSupplier(binding);
77+
case ClassTreeImpl t -> t.typeSymbol = binding == null ? SemanticValues.UNKNOWN_TYPE_SYMBOL
78+
: new EcjSemanticAttachment<>(binding, sema::typeSymbol);
79+
case TypeParameterTreeImpl t -> t.typeSymbol = sema.symbolSupplier(binding);
80+
default -> throw new IllegalArgumentException("No type attachment: " + tree.getClass());
81+
}
82+
if (tree instanceof KeywordThis t) {
83+
t.symbolSupplier = binding == null ? SemanticValues.UNKNOWN_SYMBOL
84+
: new EcjSemanticAttachment<>(binding, b -> sema.typeSymbol(b).thisSymbol);
85+
} else if (tree instanceof KeywordSuper t) {
86+
t.symbolSupplier = binding == null ? SemanticValues.UNKNOWN_SYMBOL
87+
: new EcjSemanticAttachment<>(binding, b -> sema.typeSymbol(b).superSymbol);
88+
}
89+
}
90+
91+
static void setSymbol(JSema sema, JavaTree tree, @Nullable IBinding binding) {
92+
switch (tree) {
93+
case MethodTreeImpl t -> t.methodSymbol = sema.methodSupplier((IMethodBinding) binding);
94+
case MethodInvocationTreeImpl t -> t.methodSymbolSupplier = sema.methodSupplier((IMethodBinding) binding);
95+
case LambdaExpressionTreeImpl t -> t.methodSymbol = sema.methodSupplier((IMethodBinding) binding);
96+
case VariableTreeImpl t -> t.variableSymbol = sema.symbolSupplier(binding);
97+
case IdentifierTreeImpl t -> t.symbolSupplier = sema.symbolSupplier(binding);
98+
case JavaTree.ImportTreeImpl t -> t.symbolSupplier = binding == null || binding.getKind() == IBinding.PACKAGE
99+
|| binding.getKind() == IBinding.MODULE ? () -> null : sema.symbolSupplier(binding);
100+
default -> throw new IllegalArgumentException("No symbol attachment: " + tree.getClass());
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)