From 860298082aeb92b660ed93d29d5a171f17a89203 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Tue, 6 Aug 2024 11:03:30 +0100 Subject: [PATCH] GRAPH-775 annotation processing fix (#732) * Fix exception reporting in javac plugin Without closing the print writer, empty message was produced. * (root cause) add unary tree to semanticdb and handle it * Allow regenerating a subset of snapshots * Add link to JLS --- .../scip_semanticdb/SignatureFormatter.java | 28 ++++++++++ .../semanticdb_javac/SemanticdbBuilders.java | 9 ++++ .../src/main/protobuf/semanticdb.proto | 18 +++++++ .../SemanticdbTaskListener.java | 4 +- .../semanticdb_javac/SemanticdbTrees.java | 42 ++++++++++++++- .../java/minimized/AnnotationParameters.java | 23 ++++++++ .../java/minimized/AnnotationParameters.java | 54 +++++++++++++++++++ .../src/main/scala/tests/SaveSnapshots.scala | 16 +++++- 8 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 tests/minimized/src/main/java/minimized/AnnotationParameters.java create mode 100644 tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java 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 ce1133918..aec78d52b 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 @@ -468,11 +468,39 @@ private String formatTree(Tree tree) { return formatTree(tree.getAssignTree().getLhs()) + " = " + formatTree(tree.getAssignTree().getRhs()); + } else if (tree.hasUnaryopTree()) { + return formatUnaryOperation(tree.getUnaryopTree()); } throw new IllegalArgumentException("tree was of unexpected type " + tree); } + private String formatUnaryOperation(UnaryOperatorTree tree) { + String formattedValue = formatTree(tree.getTree()); + switch (tree.getOp()) { + case UNARY_MINUS: + return "-" + formattedValue; + case UNARY_PLUS: + return "-" + formattedValue; + case UNARY_POSTFIX_INCREMENT: + return formattedValue + "++"; + case UNARY_POSTFIX_DECREMENT: + return formattedValue + "--"; + case UNARY_PREFIX_DECREMENT: + return "--" + formattedValue; + case UNARY_PREFIX_INCREMENT: + return "++" + formattedValue; + + case UNARY_BITWISE_COMPLEMENT: + return "~" + formattedValue; + case UNARY_LOGICAL_COMPLEMENT: + return "!" + formattedValue; + } + + throw new IllegalArgumentException( + "unary operation of unexpected type" + tree.getOp().toString()); + } + private String formatConstant(Constant constant) { if (constant.hasUnitConstant()) { return isScala ? "()" : "scala.Unit()"; 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 492572a1a..da11befd4 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 @@ -146,6 +146,15 @@ public static Semanticdb.BinaryOperatorTree binopTree( .build(); } + public static Semanticdb.Tree tree(Semanticdb.UnaryOperatorTree unaryOperatorTree) { + return Semanticdb.Tree.newBuilder().setUnaryopTree(unaryOperatorTree).build(); + } + + public static Semanticdb.UnaryOperatorTree unaryOpTree( + Semanticdb.UnaryOperator operator, Semanticdb.Tree rhs) { + return Semanticdb.UnaryOperatorTree.newBuilder().setOp(operator).setTree(rhs).build(); + } + public static Semanticdb.Tree tree(Semanticdb.AssignTree assignTree) { return Semanticdb.Tree.newBuilder().setAssignTree(assignTree).build(); } diff --git a/semanticdb-java/src/main/protobuf/semanticdb.proto b/semanticdb-java/src/main/protobuf/semanticdb.proto index 99857524a..5f5ec5b41 100644 --- a/semanticdb-java/src/main/protobuf/semanticdb.proto +++ b/semanticdb-java/src/main/protobuf/semanticdb.proto @@ -297,6 +297,7 @@ message Tree { AnnotationTree annotation_tree = 9; AssignTree assign_tree = 10; BinaryOperatorTree binop_tree = 11; + UnaryOperatorTree unaryop_tree = 12; // -- OUT OF SPEC -- // } } @@ -378,6 +379,23 @@ enum BinaryOperator { GREATER_THAN_EQUAL = 17; LESS_THAN_EQUAL = 18; } + +// https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15 +message UnaryOperatorTree { + UnaryOperator op = 1; + Tree tree = 2; +} + +enum UnaryOperator { + UNARY_MINUS = 0; + UNARY_PLUS = 1; + UNARY_POSTFIX_INCREMENT = 2; + UNARY_POSTFIX_DECREMENT = 3; + UNARY_PREFIX_DECREMENT = 4; + UNARY_PREFIX_INCREMENT = 5; + UNARY_BITWISE_COMPLEMENT = 6; + UNARY_LOGICAL_COMPLEMENT = 7; +} // -- OUT OF SPEC -- // message Constant { diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTaskListener.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTaskListener.java index 3844d0b3c..f2594c76f 100644 --- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTaskListener.java +++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTaskListener.java @@ -83,7 +83,9 @@ public void finished(TaskEvent e) { // exception, it just prints the location with an empty message. private void reportException(Throwable exception, TaskEvent e) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - exception.printStackTrace(new PrintWriter(baos)); + PrintWriter pw = new PrintWriter(baos); + exception.printStackTrace(pw); + pw.close(); reporter.error(baos.toString(), e.getCompilationUnit(), e.getCompilationUnit()); } 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 93c0bd609..90e5889d2 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 @@ -8,6 +8,7 @@ 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; @@ -78,7 +79,8 @@ public Semanticdb.AnnotationTree annotationBuilder(AnnotationTree annotation) { ArrayList params = new ArrayList<>(annotation.getArguments().size()); for (ExpressionTree param : annotation.getArguments()) { - // anecdotally not always AssignmentTree in some situations when a compilation unit can't + // anecdotally not always AssignmentTree in some situations when a compilation + // unit can't // resolve symbols fully if (param instanceof AssignmentTree) { AssignmentTree assign = (AssignmentTree) param; @@ -152,6 +154,12 @@ private Semanticdb.Tree annotationParameter(ExpressionTree expr) { annotationParameter(binExpr.getLeftOperand()), semanticdbBinaryOperator(expr.getKind()), annotationParameter(binExpr.getRightOperand()))); + } else if (expr instanceof UnaryTree) { + UnaryTree unaryExpr = (UnaryTree) expr; + return tree( + unaryOpTree( + semanticdbUnaryOperator(unaryExpr.getKind()), + annotationParameter(unaryExpr.getExpression()))); } throw new IllegalArgumentException( semanticdbUri @@ -206,4 +214,36 @@ private Semanticdb.BinaryOperator semanticdbBinaryOperator(Tree.Kind kind) { semanticdbUri + ": unexpected binary expression operator kind " + kind); } } + + private Semanticdb.UnaryOperator semanticdbUnaryOperator(Tree.Kind kind) { + switch (kind) { + case UNARY_MINUS: + return Semanticdb.UnaryOperator.UNARY_MINUS; + + case UNARY_PLUS: + return Semanticdb.UnaryOperator.UNARY_PLUS; + + case POSTFIX_INCREMENT: + return Semanticdb.UnaryOperator.UNARY_POSTFIX_INCREMENT; + + case POSTFIX_DECREMENT: + return Semanticdb.UnaryOperator.UNARY_POSTFIX_DECREMENT; + + case PREFIX_INCREMENT: + return Semanticdb.UnaryOperator.UNARY_PREFIX_INCREMENT; + + case PREFIX_DECREMENT: + return Semanticdb.UnaryOperator.UNARY_PREFIX_DECREMENT; + + case BITWISE_COMPLEMENT: + return Semanticdb.UnaryOperator.UNARY_BITWISE_COMPLEMENT; + + case LOGICAL_COMPLEMENT: + return Semanticdb.UnaryOperator.UNARY_LOGICAL_COMPLEMENT; + + default: + throw new IllegalStateException( + semanticdbUri + ": unexpected unary expression operator kind " + kind); + } + } } diff --git a/tests/minimized/src/main/java/minimized/AnnotationParameters.java b/tests/minimized/src/main/java/minimized/AnnotationParameters.java new file mode 100644 index 000000000..d2049d3f4 --- /dev/null +++ b/tests/minimized/src/main/java/minimized/AnnotationParameters.java @@ -0,0 +1,23 @@ +package minimized; + + +@interface Bar { + double value(); +} + +@interface BarB { + boolean value(); +} + +interface Foo { + @Bar(-1d) + double test(); + + @Bar(~5) + @SuppressWarnings(value = "unchecked") + double test2(); + + @BarB(!true) + double test3(); +} + 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 new file mode 100644 index 000000000..fbb0fbf32 --- /dev/null +++ b/tests/snapshots/src/main/generated/tests/minimized/src/main/java/minimized/AnnotationParameters.java @@ -0,0 +1,54 @@ +package minimized; + + +@interface Bar { +// ^^^ definition semanticdb maven . . minimized/Bar# +// display_name Bar +// signature_documentation java @interface Bar +// kind Interface +// relationship is_implementation semanticdb maven jdk 11 java/lang/annotation/Annotation# + double value(); +} + +@interface BarB { +// ^^^^ definition semanticdb maven . . minimized/BarB# +// display_name BarB +// signature_documentation java @interface BarB +// kind Interface +// relationship is_implementation semanticdb maven jdk 11 java/lang/annotation/Annotation# + boolean value(); +} + +interface Foo { +// ^^^ definition semanticdb maven . . minimized/Foo# +// display_name Foo +// signature_documentation java interface Foo +// kind Interface + @Bar(-1d) +// ^^^ reference semanticdb maven . . minimized/Bar# + double test(); +// ^^^^ definition semanticdb maven . . minimized/Foo#test(). +// display_name test +// signature_documentation java @Bar(-1.0)\npublic abstract double test() +// kind AbstractMethod + + @Bar(~5) +// ^^^ reference semanticdb maven . . minimized/Bar# + @SuppressWarnings(value = "unchecked") +// ^^^^^^^^^^^^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings# +// ^^^^^ reference semanticdb maven jdk 11 java/lang/SuppressWarnings#value(). + double test2(); +// ^^^^^ definition semanticdb maven . . minimized/Foo#test2(). +// display_name test2 +// signature_documentation java @Bar(~5)\n@SuppressWarnings("unchecked")\npublic abstract double test2() +// kind AbstractMethod + + @BarB(!true) +// ^^^^ reference semanticdb maven . . minimized/BarB# + double test3(); +// ^^^^^ definition semanticdb maven . . minimized/Foo#test3(). +// display_name test3 +// signature_documentation java @BarB(!true)\npublic abstract double test3() +// kind AbstractMethod +} + diff --git a/tests/snapshots/src/main/scala/tests/SaveSnapshots.scala b/tests/snapshots/src/main/scala/tests/SaveSnapshots.scala index 2859051f5..d489fb7e4 100644 --- a/tests/snapshots/src/main/scala/tests/SaveSnapshots.scala +++ b/tests/snapshots/src/main/scala/tests/SaveSnapshots.scala @@ -3,7 +3,19 @@ package tests object SaveSnapshots { def main(args: Array[String]): Unit = { val expectDirectory = tests.snapshots.BuildInfo.snapshotDirectory.toPath - SemanticdbJavacSnapshotGenerator - .run(SnapshotContext(expectDirectory), new SaveSnapshotHandler) + val mapping = Map( + "minimized" -> new MinimizedSnapshotScipGenerator(), + "library" -> new LibrarySnapshotGenerator() + ) + + val enabledGenerators = + if (args.isEmpty) + mapping.values.toList + else + args.flatMap(mapping.get).toList + + val generator = new AggregateSnapshotGenerator(enabledGenerators) + + generator.run(SnapshotContext(expectDirectory), new SaveSnapshotHandler) } }