From 30114edcc3016e4dfd3c081db8be3833834d6224 Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Fri, 23 Apr 2021 15:14:28 +0100 Subject: [PATCH] add support for binary operator trees in annotations --- .../lsif_semanticdb/SignatureFormatter.java | 52 ++++++++++++++++ .../src/main/protobuf/semanticdb.proto | 29 +++++++++ .../semanticdb_javac/SemanticdbVisitor.java | 62 +++++++++++++++++-- .../src/main/java/minimized/InnerClasses.java | 12 ++++ .../generated/minimized/InnerClasses.java | 25 +++++++- 5 files changed, 174 insertions(+), 6 deletions(-) diff --git a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/SignatureFormatter.java b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/SignatureFormatter.java index f0e1d0f4..ba2d7c84 100644 --- a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/SignatureFormatter.java +++ b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/SignatureFormatter.java @@ -315,6 +315,12 @@ private String formatTree(Tree tree) { throw new IllegalArgumentException( "unexpected apply tree function " + tree.getApplyTree().getFunction()); } + } else if (tree.hasBinopTree()) { + return formatTree(tree.getBinopTree().getLhs()) + + " " + + formatBinaryOperator(tree.getBinopTree().getOp()) + + " " + + formatTree(tree.getBinopTree().getRhs()); } throw new IllegalArgumentException("tree was of unexpected type " + tree); @@ -343,6 +349,52 @@ private String formatConstant(Constant constant) { throw new IllegalArgumentException("constant was not of known type " + constant); } + private String formatBinaryOperator(BinaryOperator op) { + switch (op) { + case PLUS: + return "+"; + case MINUS: + return "-"; + case MULTIPLY: + return "*"; + case DIVIDE: + return "/"; + case REMAINDER: + return "%"; + case GREATER_THAN: + return ">"; + case LESS_THAN: + return "<"; + case AND: + return "&"; + case XOR: + return "^"; + case OR: + return "|"; + case CONDITIONAL_AND: + return "&&"; + case CONDITIONAL_OR: + return "||"; + case SHIFT_LEFT: + return "<<"; + case SHIFT_RIGHT: + return ">>"; + case SHIFT_RIGHT_UNSIGNED: + return ">>>"; + case EQUAL_TO: + return "=="; + case NOT_EQUAL_TO: + return "!="; + case GREATER_THAN_EQUAL: + return ">="; + case LESS_THAN_EQUAL: + return "<="; + case UNRECOGNIZED: + throw new IllegalArgumentException("unexpected binary operator " + op); + } + return null; + } + private String formatType(Type type) { StringBuilder b = new StringBuilder(); if (type.hasTypeRef()) { diff --git a/semanticdb-java/src/main/protobuf/semanticdb.proto b/semanticdb-java/src/main/protobuf/semanticdb.proto index dd277fdd..4195d906 100644 --- a/semanticdb-java/src/main/protobuf/semanticdb.proto +++ b/semanticdb-java/src/main/protobuf/semanticdb.proto @@ -194,6 +194,7 @@ message Tree { // -- OUT OF SPEC -- // AnnotationTree annotation_tree = 9; AssignTree assign_tree = 10; + BinaryOperatorTree binop_tree = 11; // -- OUT OF SPEC -- // } } @@ -230,6 +231,34 @@ message AssignTree { Tree lhs = 1; Tree rhs = 2; } + +message BinaryOperatorTree { + Tree lhs = 1; + BinaryOperator op = 2; + Tree rhs = 3; +} + +enum BinaryOperator { + PLUS = 0; + MINUS = 1; + MULTIPLY = 2; + DIVIDE = 3; + REMAINDER = 4; + GREATER_THAN = 5; + LESS_THAN = 6; + AND = 7; + XOR = 8; + OR = 9; + CONDITIONAL_AND = 10; + CONDITIONAL_OR = 11; + SHIFT_LEFT = 12; + SHIFT_RIGHT = 13; + SHIFT_RIGHT_UNSIGNED = 14; + EQUAL_TO = 15; + NOT_EQUAL_TO = 16; + GREATER_THAN_EQUAL = 17; + LESS_THAN_EQUAL = 18; +} // -- OUT OF SPEC -- // message Constant { 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 89ea09fa..b15a736d 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 @@ -19,10 +19,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import static com.sourcegraph.semanticdb_javac.SemanticdbTypeVisitor.ARRAY_SYMBOL; @@ -469,7 +466,9 @@ private Semanticdb.Tree.Builder semanticdbAnnotationParameter(JCTree.JCExpressio break; case CHAR: constantBuilder.setCharConstant( - Semanticdb.CharConstant.newBuilder().setValue((Character) rhs.value).build()); + Semanticdb.CharConstant.newBuilder() + .setValue(Character.forDigit((Integer) rhs.value, 10)) + .build()); break; case FLOAT: constantBuilder.setFloatConstant( @@ -516,6 +515,13 @@ private Semanticdb.Tree.Builder semanticdbAnnotationParameter(JCTree.JCExpressio Semanticdb.IdTree.newBuilder() .setSymbol(globals.semanticdbSymbol(((JCTree.JCIdent) expr).sym, locals)) .build()); + } else if (expr instanceof JCTree.JCBinary) { + Semanticdb.BinaryOperatorTree.Builder binOp = Semanticdb.BinaryOperatorTree.newBuilder(); + JCTree.JCBinary binExpr = (JCTree.JCBinary) expr; + binOp.setLhs(semanticdbAnnotationParameter(binExpr.lhs)); + binOp.setOp(semanticdbBinaryOperator(expr.getKind())); + binOp.setRhs(semanticdbAnnotationParameter(binExpr.rhs)); + return Semanticdb.Tree.newBuilder().setBinopTree(binOp.build()); } throw new IllegalArgumentException( @@ -559,6 +565,52 @@ private Semanticdb.Access semanticdbAccess(Symbol sym) { } } + private Semanticdb.BinaryOperator semanticdbBinaryOperator(Tree.Kind kind) { + switch (kind) { + case PLUS: + return Semanticdb.BinaryOperator.PLUS; + case MINUS: + return Semanticdb.BinaryOperator.MINUS; + case MULTIPLY: + return Semanticdb.BinaryOperator.MULTIPLY; + case DIVIDE: + return Semanticdb.BinaryOperator.DIVIDE; + case REMAINDER: + return Semanticdb.BinaryOperator.REMAINDER; + case LESS_THAN: + return Semanticdb.BinaryOperator.LESS_THAN; + case GREATER_THAN: + return Semanticdb.BinaryOperator.GREATER_THAN; + case LEFT_SHIFT: + return Semanticdb.BinaryOperator.SHIFT_LEFT; + case RIGHT_SHIFT: + return Semanticdb.BinaryOperator.SHIFT_RIGHT; + case UNSIGNED_RIGHT_SHIFT: + return Semanticdb.BinaryOperator.SHIFT_RIGHT_UNSIGNED; + case EQUAL_TO: + return Semanticdb.BinaryOperator.EQUAL_TO; + case NOT_EQUAL_TO: + return Semanticdb.BinaryOperator.NOT_EQUAL_TO; + case LESS_THAN_EQUAL: + return Semanticdb.BinaryOperator.LESS_THAN_EQUAL; + case GREATER_THAN_EQUAL: + return Semanticdb.BinaryOperator.GREATER_THAN_EQUAL; + case CONDITIONAL_AND: + return Semanticdb.BinaryOperator.CONDITIONAL_AND; + case CONDITIONAL_OR: + return Semanticdb.BinaryOperator.CONDITIONAL_OR; + case AND: + return Semanticdb.BinaryOperator.AND; + case OR: + return Semanticdb.BinaryOperator.OR; + case XOR: + return Semanticdb.BinaryOperator.XOR; + default: + throw new IllegalStateException( + semanticdbUri() + ": unexpected binary expression operator kind " + kind); + } + } + private String semanticdbUri() { Path absolutePath = Paths.get(event.getSourceFile().toUri()); Path relativePath = options.sourceroot.relativize(absolutePath); diff --git a/tests/minimized/src/main/java/minimized/InnerClasses.java b/tests/minimized/src/main/java/minimized/InnerClasses.java index 07f87879..fe111e37 100644 --- a/tests/minimized/src/main/java/minimized/InnerClasses.java +++ b/tests/minimized/src/main/java/minimized/InnerClasses.java @@ -4,6 +4,11 @@ public class InnerClasses { private final int exampleField; + private static final String STRING = "asdf"; + + private static final int top = 5; + private static final int bottom = 10; + public InnerClasses(int exampleField) { this.exampleField = exampleField; } @@ -18,7 +23,14 @@ public interface InnerInterface { B apply(A a); } + public @interface InnerAnnotation { + int value(); + } + + @SuppressWarnings(STRING + " ") + @InnerAnnotation(top / bottom) public static class InnerStaticClass { + public static void innerStaticMethod() {} } diff --git a/tests/snapshots/src/main/generated/minimized/InnerClasses.java b/tests/snapshots/src/main/generated/minimized/InnerClasses.java index 61309437..e8f75acd 100644 --- a/tests/snapshots/src/main/generated/minimized/InnerClasses.java +++ b/tests/snapshots/src/main/generated/minimized/InnerClasses.java @@ -6,6 +6,15 @@ public class InnerClasses { private final int exampleField; // ^^^^^^^^^^^^ definition minimized/InnerClasses#exampleField. private final int exampleField + private static final String STRING = "asdf"; +// ^^^^^^ reference java/lang/String# +// ^^^^^^ definition minimized/InnerClasses#STRING. private static final String STRING + + private static final int top = 5; +// ^^^ definition minimized/InnerClasses#top. private static final int top + private static final int bottom = 10; +// ^^^^^^ definition minimized/InnerClasses#bottom. private static final int bottom + public InnerClasses(int exampleField) { // ^^^^^^^^^^^^ definition minimized/InnerClasses#``(). public InnerClasses(int exampleField) // ^^^^^^^^^^^^ definition local0 int exampleField @@ -36,9 +45,23 @@ public interface InnerInterface { // ^ definition local1 A a } + public @interface InnerAnnotation { +// ^^^^^^^^^^^^^^^ definition minimized/InnerClasses#InnerAnnotation# public @interface InnerAnnotation + int value(); +// ^^^^^ definition minimized/InnerClasses#InnerAnnotation#value(). public abstract int value() + } + + @SuppressWarnings(STRING + " ") +// ^^^^^^^^^^^^^^^^ reference java/lang/SuppressWarnings# +// ^^^^^^ reference minimized/InnerClasses#STRING. + @InnerAnnotation(top / bottom) +// ^^^^^^^^^^^^^^^ reference minimized/InnerClasses#InnerAnnotation# +// ^^^ reference minimized/InnerClasses#top. +// ^^^^^^ reference minimized/InnerClasses#bottom. public static class InnerStaticClass { -// ^^^^^^^^^^^^^^^^ definition minimized/InnerClasses#InnerStaticClass# public static class InnerStaticClass +// ^^^^^^^^^^^^^^^^ definition minimized/InnerClasses#InnerStaticClass# @SuppressWarnings(STRING + " ") @InnerAnnotation(top / bottom) public static class InnerStaticClass // ^^^^^^^^^^^^^^^^ definition minimized/InnerClasses#InnerStaticClass#``(). public InnerStaticClass() + public static void innerStaticMethod() {} // ^^^^^^^^^^^^^^^^^ definition minimized/InnerClasses#InnerStaticClass#innerStaticMethod(). public static void innerStaticMethod() }