diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatter.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatter.java index aec78d52..fc306ad2 100644 --- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatter.java +++ b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatter.java @@ -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); diff --git a/semanticdb-java/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbBuilders.java b/semanticdb-java/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbBuilders.java index da11befd..d592efaf 100644 --- a/semanticdb-java/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbBuilders.java +++ b/semanticdb-java/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbBuilders.java @@ -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(); @@ -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 parameters) { return Semanticdb.AnnotationTree.newBuilder().setTpe(type).addAllParameters(parameters).build(); } + // SemanticDB Constants public static Semanticdb.Constant stringConst(String value) { @@ -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)) diff --git a/semanticdb-java/src/main/protobuf/semanticdb.proto b/semanticdb-java/src/main/protobuf/semanticdb.proto index 5f5ec5b4..2e72263c 100644 --- a/semanticdb-java/src/main/protobuf/semanticdb.proto +++ b/semanticdb-java/src/main/protobuf/semanticdb.proto @@ -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 -- // } } @@ -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; diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTrees.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTrees.java index a95a74fb..f78b5abe 100644 --- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTrees.java +++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTrees.java @@ -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; @@ -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; @@ -52,6 +40,7 @@ public SemanticdbTrees( private final Types types; private final Trees trees; private final HashMap nodes; + private final SemanticdbTypeVisitor typeVisitor; public List annotations(Tree node) { if (!(node instanceof ClassTree) @@ -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); @@ -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); @@ -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) { diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java index cebd32f9..f8298532 100644 --- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java +++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java @@ -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; diff --git a/tests/minimized/src/main/java/minimized/AnnotationParameters.java b/tests/minimized/src/main/java/minimized/AnnotationParameters.java index af376dff..1ec1faf3 100644 --- a/tests/minimized/src/main/java/minimized/AnnotationParameters.java +++ b/tests/minimized/src/main/java/minimized/AnnotationParameters.java @@ -12,6 +12,11 @@ String value() default ""; } + +@interface BarRef{ + SuppressWarnings value(); +} + interface Foo { @Bar(-1d) double test(); @@ -25,4 +30,12 @@ interface Foo { @Nullable(("what")) Foo test4(); + + @Bar((double) -1) + double testCast(); +} + +interface TestRef { + @BarRef(@SuppressWarnings(value = "unchecked")) + abstract double testCase(); } diff --git a/tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java b/tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java index d2c068fa..8dc8786f 100644 --- a/tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java +++ b/tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java @@ -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 @@ -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 }