Skip to content

Commit 6c183d8

Browse files
Support cast tree in annotation parameters (#750)
1 parent 439a0f9 commit 6c183d8

File tree

7 files changed

+110
-24
lines changed

7 files changed

+110
-24
lines changed

scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatter.java

+6
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,12 @@ private String formatTree(Tree tree) {
470470
+ formatTree(tree.getAssignTree().getRhs());
471471
} else if (tree.hasUnaryopTree()) {
472472
return formatUnaryOperation(tree.getUnaryopTree());
473+
} else if (tree.hasCastTree()) {
474+
return "("
475+
+ formatType(tree.getCastTree().getTpe())
476+
+ ")"
477+
+ " "
478+
+ formatTree(tree.getCastTree().getValue());
473479
}
474480

475481
throw new IllegalArgumentException("tree was of unexpected type " + tree);

semanticdb-java/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbBuilders.java

+15
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ public static Semanticdb.Tree tree(Semanticdb.UnaryOperatorTree unaryOperatorTre
150150
return Semanticdb.Tree.newBuilder().setUnaryopTree(unaryOperatorTree).build();
151151
}
152152

153+
public static Semanticdb.Tree tree(Semanticdb.CastTree castTree) {
154+
return Semanticdb.Tree.newBuilder().setCastTree(castTree).build();
155+
}
156+
153157
public static Semanticdb.UnaryOperatorTree unaryOpTree(
154158
Semanticdb.UnaryOperator operator, Semanticdb.Tree rhs) {
155159
return Semanticdb.UnaryOperatorTree.newBuilder().setOp(operator).setTree(rhs).build();
@@ -163,10 +167,15 @@ public static Semanticdb.AssignTree assignTree(Semanticdb.Tree lhs, Semanticdb.T
163167
return Semanticdb.AssignTree.newBuilder().setLhs(lhs).setRhs(rhs).build();
164168
}
165169

170+
public static Semanticdb.CastTree castTree(Semanticdb.Type type, Semanticdb.Tree value) {
171+
return Semanticdb.CastTree.newBuilder().setTpe(type).setValue(value).build();
172+
}
173+
166174
public static Semanticdb.AnnotationTree annotationTree(
167175
Semanticdb.Type type, Iterable<Semanticdb.Tree> parameters) {
168176
return Semanticdb.AnnotationTree.newBuilder().setTpe(type).addAllParameters(parameters).build();
169177
}
178+
170179
// SemanticDB Constants
171180

172181
public static Semanticdb.Constant stringConst(String value) {
@@ -181,6 +190,12 @@ public static Semanticdb.Constant doubleConst(Double value) {
181190
.build();
182191
}
183192

193+
public static Semanticdb.Constant nullConst() {
194+
return Semanticdb.Constant.newBuilder()
195+
.setNullConstant(Semanticdb.NullConstant.newBuilder())
196+
.build();
197+
}
198+
184199
public static Semanticdb.Constant floatConst(Float value) {
185200
return Semanticdb.Constant.newBuilder()
186201
.setFloatConstant(Semanticdb.FloatConstant.newBuilder().setValue(value))

semanticdb-java/src/main/protobuf/semanticdb.proto

+7
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ message Tree {
298298
AssignTree assign_tree = 10;
299299
BinaryOperatorTree binop_tree = 11;
300300
UnaryOperatorTree unaryop_tree = 12;
301+
CastTree cast_tree = 13;
301302
// -- OUT OF SPEC -- //
302303
}
303304
}
@@ -347,6 +348,12 @@ message AnnotationTree {
347348
repeated Tree parameters = 2;
348349
}
349350

351+
352+
message CastTree {
353+
Type tpe = 1;
354+
Tree value = 2;
355+
}
356+
350357
message AssignTree {
351358
Tree lhs = 1;
352359
Tree rhs = 2;

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTrees.java

+29-24
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
11
package com.sourcegraph.semanticdb_javac;
22

3-
import com.sun.source.tree.Tree;
3+
import com.sun.source.tree.*;
44
import com.sun.source.util.Trees;
55
import javax.lang.model.element.Element;
66
import javax.lang.model.util.Types;
7+
import javax.lang.model.type.TypeMirror;
78
import com.sun.source.util.TreePath;
89
import com.sun.source.tree.Tree;
910
import com.sun.source.tree.Tree.Kind;
10-
import com.sun.source.tree.BinaryTree;
11-
import com.sun.source.tree.UnaryTree;
12-
import com.sun.source.tree.AssignmentTree;
13-
import com.sun.source.tree.MemberSelectTree;
14-
import com.sun.source.tree.ClassTree;
15-
import com.sun.source.tree.VariableTree;
16-
import com.sun.source.tree.MethodTree;
17-
import com.sun.source.tree.ModifiersTree;
18-
import com.sun.source.tree.IdentifierTree;
19-
import com.sun.source.tree.ExpressionTree;
20-
import com.sun.source.tree.LiteralTree;
21-
import com.sun.source.tree.NewArrayTree;
22-
import com.sun.source.tree.AnnotationTree;
23-
import com.sun.source.tree.ParenthesizedTree;
2411

2512
import java.util.HashMap;
2613
import java.util.ArrayList;
@@ -44,6 +31,7 @@ public SemanticdbTrees(
4431
this.types = types;
4532
this.trees = trees;
4633
this.nodes = nodes;
34+
this.typeVisitor = new SemanticdbTypeVisitor(globals, locals, types);
4735
}
4836

4937
private final GlobalSymbolsCache globals;
@@ -52,6 +40,7 @@ public SemanticdbTrees(
5240
private final Types types;
5341
private final Trees trees;
5442
private final HashMap<Tree, TreePath> nodes;
43+
private final SemanticdbTypeVisitor typeVisitor;
5544

5645
public List<Semanticdb.AnnotationTree> annotations(Tree node) {
5746
if (!(node instanceof ClassTree)
@@ -100,11 +89,15 @@ public Semanticdb.AnnotationTree annotationBuilder(AnnotationTree annotation) {
10089
TreePath annotationTreePath = nodes.get(annotation);
10190
Element annotationSym = trees.getElement(annotationTreePath);
10291

103-
Semanticdb.Type type =
104-
new SemanticdbTypeVisitor(globals, locals, types).semanticdbType(annotationSym.asType());
92+
Semanticdb.Type type = typeVisitor.semanticdbType(annotationSym.asType());
10593
return annotationTree(type, params);
10694
}
10795

96+
private TypeMirror getTreeType(Tree tree) {
97+
TreePath path = nodes.get(tree);
98+
return trees.getTypeMirror(path);
99+
}
100+
108101
private Semanticdb.Tree annotationParameter(ExpressionTree expr) {
109102
if (expr instanceof MemberSelectTree) {
110103
TreePath expressionTreePath = nodes.get(expr);
@@ -125,7 +118,12 @@ private Semanticdb.Tree annotationParameter(ExpressionTree expr) {
125118
// Literals can either be a primitive or String
126119
Object value = ((LiteralTree) expr).getValue();
127120
final Semanticdb.Constant constant;
128-
if (value instanceof String) constant = stringConst((String) value);
121+
// Technically, annotation parameter values cannot be null,
122+
// according to JLS: https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.7.1
123+
// But this codepath is still possible to hit when compiling invalid code - and
124+
// we should handle the null const case in order to fail more gracefully
125+
if (value == null) constant = nullConst();
126+
else if (value instanceof String) constant = stringConst((String) value);
129127
else if (value instanceof Boolean) constant = booleanConst((Boolean) value);
130128
else if (value instanceof Byte) constant = byteConst((Byte) value);
131129
else if (value instanceof Short) constant = shortConst((Short) value);
@@ -164,13 +162,20 @@ private Semanticdb.Tree annotationParameter(ExpressionTree expr) {
164162
} else if (expr instanceof ParenthesizedTree) {
165163
ParenthesizedTree parenExpr = (ParenthesizedTree) expr;
166164
return annotationParameter(parenExpr.getExpression());
165+
} else if (expr instanceof TypeCastTree) {
166+
TypeCastTree tree = (TypeCastTree) expr;
167+
return tree(
168+
castTree(
169+
typeVisitor.semanticdbType(getTreeType(tree.getType())),
170+
annotationParameter(tree.getExpression())));
171+
} else {
172+
throw new IllegalArgumentException(
173+
semanticdbUri
174+
+ ": annotation parameter rhs was of unexpected tree node type "
175+
+ expr.getClass()
176+
+ "\n"
177+
+ expr);
167178
}
168-
throw new IllegalArgumentException(
169-
semanticdbUri
170-
+ ": annotation parameter rhs was of unexpected tree node type "
171-
+ expr.getClass()
172-
+ "\n"
173-
+ expr);
174179
}
175180

176181
private Semanticdb.BinaryOperator semanticdbBinaryOperator(Tree.Kind kind) {

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.sun.source.tree.ExpressionTree;
1616
import com.sun.source.tree.NewClassTree;
1717
import com.sun.source.tree.MemberSelectTree;
18+
import com.sun.source.tree.TypeCastTree;
1819
import com.sun.source.tree.TypeParameterTree;
1920
import com.sun.source.tree.ParameterizedTypeTree;
2021

tests/minimized/src/main/java/minimized/AnnotationParameters.java

+13
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
String value() default "";
1313
}
1414

15+
16+
@interface BarRef{
17+
SuppressWarnings value();
18+
}
19+
1520
interface Foo {
1621
@Bar(-1d)
1722
double test();
@@ -25,4 +30,12 @@ interface Foo {
2530

2631
@Nullable(("what"))
2732
Foo test4();
33+
34+
@Bar((double) -1)
35+
double testCast();
36+
}
37+
38+
interface TestRef {
39+
@BarRef(@SuppressWarnings(value = "unchecked"))
40+
abstract double testCase();
2841
}

tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java

+39
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@
4040
// kind AbstractMethod
4141
}
4242

43+
44+
@interface BarRef{
45+
// ^^^^^^ definition semanticdb maven . . minimized/BarRef#
46+
// display_name BarRef
47+
// signature_documentation java @interface BarRef
48+
// kind Interface
49+
// relationship is_implementation semanticdb maven jdk 11 java/lang/annotation/Annotation#
50+
SuppressWarnings value();
51+
//^^^^^^^^^^^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#
52+
// ^^^^^ definition semanticdb maven . . minimized/BarRef#value().
53+
// display_name value
54+
// signature_documentation java public abstract SuppressWarnings value()
55+
// kind AbstractMethod
56+
}
57+
4358
interface Foo {
4459
// ^^^ definition semanticdb maven . . minimized/Foo#
4560
// display_name Foo
@@ -80,4 +95,28 @@ interface Foo {
8095
// display_name test4
8196
// signature_documentation java @Nullable("what")\npublic abstract Foo test4()
8297
// kind AbstractMethod
98+
99+
@Bar((double) -1)
100+
//^^^ reference semanticdb maven . . minimized/Bar#
101+
double testCast();
102+
// ^^^^^^^^ definition semanticdb maven . . minimized/Foo#testCast().
103+
// display_name testCast
104+
// signature_documentation java @Bar((double) -1)\npublic abstract double testCast()
105+
// kind AbstractMethod
106+
}
107+
108+
interface TestRef {
109+
// ^^^^^^^ definition semanticdb maven . . minimized/TestRef#
110+
// display_name TestRef
111+
// signature_documentation java interface TestRef
112+
// kind Interface
113+
@BarRef(@SuppressWarnings(value = "unchecked"))
114+
//^^^^^^ reference semanticdb maven . . minimized/BarRef#
115+
// ^^^^^^^^^^^^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#
116+
// ^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#value().
117+
abstract double testCase();
118+
// ^^^^^^^^ definition semanticdb maven . . minimized/TestRef#testCase().
119+
// display_name testCase
120+
// signature_documentation java @BarRef(@SuppressWarnings("unchecked"))\npublic abstract double testCase()
121+
// kind AbstractMethod
83122
}

0 commit comments

Comments
 (0)