Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cast tree in annotation parameters #750

Merged
merged 8 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading