Skip to content

Commit

Permalink
Support cast tree in annotation parameters (#750)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonsviridov-src authored Oct 29, 2024
1 parent 439a0f9 commit 6c183d8
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ private String formatTree(Tree tree) {
+ formatTree(tree.getAssignTree().getRhs());
} else if (tree.hasUnaryopTree()) {
return formatUnaryOperation(tree.getUnaryopTree());
} else if (tree.hasCastTree()) {
return "("
+ formatType(tree.getCastTree().getTpe())
+ ")"
+ " "
+ formatTree(tree.getCastTree().getValue());
}

throw new IllegalArgumentException("tree was of unexpected type " + tree);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ public static Semanticdb.Tree tree(Semanticdb.UnaryOperatorTree unaryOperatorTre
return Semanticdb.Tree.newBuilder().setUnaryopTree(unaryOperatorTree).build();
}

public static Semanticdb.Tree tree(Semanticdb.CastTree castTree) {
return Semanticdb.Tree.newBuilder().setCastTree(castTree).build();
}

public static Semanticdb.UnaryOperatorTree unaryOpTree(
Semanticdb.UnaryOperator operator, Semanticdb.Tree rhs) {
return Semanticdb.UnaryOperatorTree.newBuilder().setOp(operator).setTree(rhs).build();
Expand All @@ -163,10 +167,15 @@ public static Semanticdb.AssignTree assignTree(Semanticdb.Tree lhs, Semanticdb.T
return Semanticdb.AssignTree.newBuilder().setLhs(lhs).setRhs(rhs).build();
}

public static Semanticdb.CastTree castTree(Semanticdb.Type type, Semanticdb.Tree value) {
return Semanticdb.CastTree.newBuilder().setTpe(type).setValue(value).build();
}

public static Semanticdb.AnnotationTree annotationTree(
Semanticdb.Type type, Iterable<Semanticdb.Tree> parameters) {
return Semanticdb.AnnotationTree.newBuilder().setTpe(type).addAllParameters(parameters).build();
}

// SemanticDB Constants

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

public static Semanticdb.Constant nullConst() {
return Semanticdb.Constant.newBuilder()
.setNullConstant(Semanticdb.NullConstant.newBuilder())
.build();
}

public static Semanticdb.Constant floatConst(Float value) {
return Semanticdb.Constant.newBuilder()
.setFloatConstant(Semanticdb.FloatConstant.newBuilder().setValue(value))
Expand Down
7 changes: 7 additions & 0 deletions semanticdb-java/src/main/protobuf/semanticdb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ message Tree {
AssignTree assign_tree = 10;
BinaryOperatorTree binop_tree = 11;
UnaryOperatorTree unaryop_tree = 12;
CastTree cast_tree = 13;
// -- OUT OF SPEC -- //
}
}
Expand Down Expand Up @@ -347,6 +348,12 @@ message AnnotationTree {
repeated Tree parameters = 2;
}


message CastTree {
Type tpe = 1;
Tree value = 2;
}

message AssignTree {
Tree lhs = 1;
Tree rhs = 2;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
package com.sourcegraph.semanticdb_javac;

import com.sun.source.tree.Tree;
import com.sun.source.tree.*;
import com.sun.source.util.Trees;
import javax.lang.model.element.Element;
import javax.lang.model.util.Types;
import javax.lang.model.type.TypeMirror;
import com.sun.source.util.TreePath;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.UnaryTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ParenthesizedTree;

import java.util.HashMap;
import java.util.ArrayList;
Expand All @@ -44,6 +31,7 @@ public SemanticdbTrees(
this.types = types;
this.trees = trees;
this.nodes = nodes;
this.typeVisitor = new SemanticdbTypeVisitor(globals, locals, types);
}

private final GlobalSymbolsCache globals;
Expand All @@ -52,6 +40,7 @@ public SemanticdbTrees(
private final Types types;
private final Trees trees;
private final HashMap<Tree, TreePath> nodes;
private final SemanticdbTypeVisitor typeVisitor;

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

Semanticdb.Type type =
new SemanticdbTypeVisitor(globals, locals, types).semanticdbType(annotationSym.asType());
Semanticdb.Type type = typeVisitor.semanticdbType(annotationSym.asType());
return annotationTree(type, params);
}

private TypeMirror getTreeType(Tree tree) {
TreePath path = nodes.get(tree);
return trees.getTypeMirror(path);
}

private Semanticdb.Tree annotationParameter(ExpressionTree expr) {
if (expr instanceof MemberSelectTree) {
TreePath expressionTreePath = nodes.get(expr);
Expand All @@ -125,7 +118,12 @@ private Semanticdb.Tree annotationParameter(ExpressionTree expr) {
// Literals can either be a primitive or String
Object value = ((LiteralTree) expr).getValue();
final Semanticdb.Constant constant;
if (value instanceof String) constant = stringConst((String) value);
// Technically, annotation parameter values cannot be null,
// according to JLS: https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.7.1
// But this codepath is still possible to hit when compiling invalid code - and
// we should handle the null const case in order to fail more gracefully
if (value == null) constant = nullConst();
else if (value instanceof String) constant = stringConst((String) value);
else if (value instanceof Boolean) constant = booleanConst((Boolean) value);
else if (value instanceof Byte) constant = byteConst((Byte) value);
else if (value instanceof Short) constant = shortConst((Short) value);
Expand Down Expand Up @@ -164,13 +162,20 @@ private Semanticdb.Tree annotationParameter(ExpressionTree expr) {
} else if (expr instanceof ParenthesizedTree) {
ParenthesizedTree parenExpr = (ParenthesizedTree) expr;
return annotationParameter(parenExpr.getExpression());
} else if (expr instanceof TypeCastTree) {
TypeCastTree tree = (TypeCastTree) expr;
return tree(
castTree(
typeVisitor.semanticdbType(getTreeType(tree.getType())),
annotationParameter(tree.getExpression())));
} else {
throw new IllegalArgumentException(
semanticdbUri
+ ": annotation parameter rhs was of unexpected tree node type "
+ expr.getClass()
+ "\n"
+ expr);
}
throw new IllegalArgumentException(
semanticdbUri
+ ": annotation parameter rhs was of unexpected tree node type "
+ expr.getClass()
+ "\n"
+ expr);
}

private Semanticdb.BinaryOperator semanticdbBinaryOperator(Tree.Kind kind) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.ParameterizedTypeTree;

Expand Down
13 changes: 13 additions & 0 deletions tests/minimized/src/main/java/minimized/AnnotationParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
String value() default "";
}


@interface BarRef{
SuppressWarnings value();
}

interface Foo {
@Bar(-1d)
double test();
Expand All @@ -25,4 +30,12 @@ interface Foo {

@Nullable(("what"))
Foo test4();

@Bar((double) -1)
double testCast();
}

interface TestRef {
@BarRef(@SuppressWarnings(value = "unchecked"))
abstract double testCase();
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@
// kind AbstractMethod
}


@interface BarRef{
// ^^^^^^ definition semanticdb maven . . minimized/BarRef#
// display_name BarRef
// signature_documentation java @interface BarRef
// kind Interface
// relationship is_implementation semanticdb maven jdk 11 java/lang/annotation/Annotation#
SuppressWarnings value();
//^^^^^^^^^^^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#
// ^^^^^ definition semanticdb maven . . minimized/BarRef#value().
// display_name value
// signature_documentation java public abstract SuppressWarnings value()
// kind AbstractMethod
}

interface Foo {
// ^^^ definition semanticdb maven . . minimized/Foo#
// display_name Foo
Expand Down Expand Up @@ -80,4 +95,28 @@ interface Foo {
// display_name test4
// signature_documentation java @Nullable("what")\npublic abstract Foo test4()
// kind AbstractMethod

@Bar((double) -1)
//^^^ reference semanticdb maven . . minimized/Bar#
double testCast();
// ^^^^^^^^ definition semanticdb maven . . minimized/Foo#testCast().
// display_name testCast
// signature_documentation java @Bar((double) -1)\npublic abstract double testCast()
// kind AbstractMethod
}

interface TestRef {
// ^^^^^^^ definition semanticdb maven . . minimized/TestRef#
// display_name TestRef
// signature_documentation java interface TestRef
// kind Interface
@BarRef(@SuppressWarnings(value = "unchecked"))
//^^^^^^ reference semanticdb maven . . minimized/BarRef#
// ^^^^^^^^^^^^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#
// ^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#value().
abstract double testCase();
// ^^^^^^^^ definition semanticdb maven . . minimized/TestRef#testCase().
// display_name testCase
// signature_documentation java @BarRef(@SuppressWarnings("unchecked"))\npublic abstract double testCase()
// kind AbstractMethod
}

0 comments on commit 6c183d8

Please sign in to comment.