From 61ed5121987aacda731da1a28fb42de841d34387 Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Tue, 13 Apr 2021 00:51:00 +0100 Subject: [PATCH 1/5] emit overridden methods for method SymbolInformation --- .../semanticdb_javac/SemanticdbPlugin.java | 6 ++++- .../SemanticdbTaskListener.java | 8 ++++-- .../semanticdb_javac/SemanticdbVisitor.java | 26 +++++++++++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbPlugin.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbPlugin.java index 83881c69..4d4915eb 100644 --- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbPlugin.java +++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbPlugin.java @@ -1,6 +1,8 @@ package com.sourcegraph.semanticdb_javac; import com.sun.source.util.*; +import com.sun.tools.javac.api.BasicJavacTask; +import com.sun.tools.javac.model.JavacTypes; /** Entrypoint of the semanticdb-javac compiler plugin. */ public class SemanticdbPlugin implements Plugin { @@ -15,12 +17,14 @@ public void init(JavacTask task, String... args) { SemanticdbReporter reporter = new SemanticdbReporter(); SemanticdbJavacOptions options = SemanticdbJavacOptions.parse(args); GlobalSymbolsCache globals = new GlobalSymbolsCache(options); + JavacTypes javacTypes = JavacTypes.instance(((BasicJavacTask) task).getContext()); if (!options.errors.isEmpty()) { for (String error : options.errors) { reporter.error(error); } } else { - task.addTaskListener(new SemanticdbTaskListener(options, task, globals, reporter)); + task.addTaskListener( + new SemanticdbTaskListener(options, task, globals, reporter, javacTypes)); } } } 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 ce7d8a92..de632542 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 @@ -4,6 +4,7 @@ import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; import com.sourcegraph.semanticdb_javac.Semanticdb; +import com.sun.tools.javac.model.JavacTypes; import java.io.IOException; import java.nio.file.Files; @@ -19,16 +20,19 @@ public final class SemanticdbTaskListener implements TaskListener { private final JavacTask task; private final GlobalSymbolsCache globals; private final SemanticdbReporter reporter; + private final JavacTypes javacTypes; public SemanticdbTaskListener( SemanticdbJavacOptions options, JavacTask task, GlobalSymbolsCache globals, - SemanticdbReporter reporter) { + SemanticdbReporter reporter, + JavacTypes javacTypes) { this.options = options; this.task = task; this.globals = globals; this.reporter = reporter; + this.javacTypes = javacTypes; } @Override @@ -51,7 +55,7 @@ private void onFinishedAnalyze(TaskEvent e) { Result path = semanticdbOutputPath(options, e); if (path.isOk()) { Semanticdb.TextDocument textDocument = - new SemanticdbVisitor(task, globals, e, options) + new SemanticdbVisitor(task, globals, e, options, javacTypes) .buildTextDocument(e.getCompilationUnit()); writeSemanticdb(path.getOrThrow(), textDocument); } else { 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 ba7b5d5a..218d9142 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 @@ -5,6 +5,7 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.model.JavacTypes; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.JCDiagnostic; @@ -19,10 +20,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; @@ -34,6 +32,7 @@ public class SemanticdbVisitor extends TreePathScanner { private final LocalSymbolsCache locals; private final JavacTask task; private final TaskEvent event; + private final JavacTypes javacTypes; private final Trees trees; private final SemanticdbJavacOptions options; private final EndPosTable endPosTable; @@ -42,12 +41,17 @@ public class SemanticdbVisitor extends TreePathScanner { private String source; public SemanticdbVisitor( - JavacTask task, GlobalSymbolsCache globals, TaskEvent event, SemanticdbJavacOptions options) { + JavacTask task, + GlobalSymbolsCache globals, + TaskEvent event, + SemanticdbJavacOptions options, + JavacTypes javacTypes) { this.task = task; this.globals = globals; // Reused cache between compilation units. this.locals = new LocalSymbolsCache(); // Fresh cache per compilation unit. this.event = event; this.options = options; + this.javacTypes = javacTypes; this.trees = Trees.instance(task); if (event.getCompilationUnit() instanceof JCTree.JCCompilationUnit) { this.endPosTable = ((JCTree.JCCompilationUnit) event.getCompilationUnit()).endPositions; @@ -113,6 +117,7 @@ private void emitSymbolInformation(Symbol sym, JCTree tree) { break; case METHOD: builder.setKind(Kind.METHOD); + builder.addAllOverriddenSymbols(semanticdbOverrides(sym)); break; case CONSTRUCTOR: builder.setKind(Kind.CONSTRUCTOR); @@ -502,6 +507,17 @@ private int semanticdbSymbolInfoProperties(Symbol sym) { return properties; } + private List semanticdbOverrides(Symbol sym) { + ArrayList overriddenSymbols = new ArrayList<>(); + Set overriddenMethods = javacTypes.getOverriddenMethods(sym); + + for (Symbol.MethodSymbol meth : overriddenMethods) { + overriddenSymbols.add(semanticdbSymbol(meth)); + } + + return overriddenSymbols; + } + private Semanticdb.Access semanticdbAccess(Symbol sym) { switch ((int) sym.flags() & Flags.AccessFlags) { case Flags.PRIVATE: From 26091278ce4b700b5c64f71f75b5ce91f09cb341 Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Wed, 14 Apr 2021 00:33:07 +0100 Subject: [PATCH 2/5] link overrides to overridden symbol's referenceResult --- .../sourcegraph/lsif_semanticdb/LsifSemanticdb.java | 12 ++++++++++++ .../com/sourcegraph/lsif_semanticdb/LsifWriter.java | 10 ++++++++++ lsif-semanticdb/src/main/protobuf/lsif.proto | 1 + 3 files changed, 23 insertions(+) diff --git a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java index 2a01a10e..fcf0abf6 100644 --- a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java +++ b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java @@ -136,6 +136,18 @@ private Integer processDocument( writer.emitHoverEdge(ids.resultSet, hoverId); } } + + // Overrides + if (symbolInformation.getOverriddenSymbolsCount() > 0) { + int[] overriddenReferenceResultIds = new int[symbolInformation.getOverriddenSymbolsCount()]; + for (int i = 0; i < symbolInformation.getOverriddenSymbolsCount(); i++) { + String overriddenSymbol = symbolInformation.getOverriddenSymbols(i); + ResultIds overriddenIds = results.getOrInsertResultSet(overriddenSymbol); + overriddenReferenceResultIds[i] = overriddenIds.referenceResult; + } + writer.emitReferenceResultsItemEdge( + ids.referenceResult, overriddenReferenceResultIds, doc.id); + } } writer.emitContains(doc.id, new ArrayList<>(rangeIds)); writer.flush(); diff --git a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifWriter.java b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifWriter.java index 4929478d..0f7e29c4 100644 --- a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifWriter.java +++ b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifWriter.java @@ -139,6 +139,16 @@ public void emitItem(int outV, int inV, int document) { emitObject(lsifEdge("item").setOutV(outV).addInVs(inV).setDocument(document)); } + public void emitReferenceResultsItemEdge(int outV, int[] inVs, int document) { + List ints = Arrays.stream(inVs).boxed().collect(Collectors.toList()); + emitObject( + lsifEdge("item") + .setOutV(outV) + .addAllInVs(ints) + .setDocument(document) + .setProperty("referenceResults")); + } + public void build() throws IOException { close(); Files.move(tmp, options.output, StandardCopyOption.REPLACE_EXISTING); diff --git a/lsif-semanticdb/src/main/protobuf/lsif.proto b/lsif-semanticdb/src/main/protobuf/lsif.proto index 7cc6fbc7..947e8528 100644 --- a/lsif-semanticdb/src/main/protobuf/lsif.proto +++ b/lsif-semanticdb/src/main/protobuf/lsif.proto @@ -25,6 +25,7 @@ message LsifObject { LsifPosition end = 20; string name = 21; string manager = 22; + string property = 23; } message LsifToolInfo { From f241007f7f6a4017e5d69aa1c03790fc71d580b6 Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Tue, 20 Apr 2021 16:51:03 +0100 Subject: [PATCH 3/5] add unit test for symbolinformation overrides --- .../src/test/scala/tests/OverridesSuite.scala | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 tests/unit/src/test/scala/tests/OverridesSuite.scala diff --git a/tests/unit/src/test/scala/tests/OverridesSuite.scala b/tests/unit/src/test/scala/tests/OverridesSuite.scala new file mode 100644 index 00000000..fdb5c625 --- /dev/null +++ b/tests/unit/src/test/scala/tests/OverridesSuite.scala @@ -0,0 +1,152 @@ +package tests + +import scala.meta.Input + +import com.sourcegraph.lsif_semanticdb.Symtab +import munit.FunSuite +import munit.TestOptions + +class OverridesSuite extends FunSuite with TempDirectories { + + val targetroot = new DirectoryFixture() + + override def munitFixtures: Seq[Fixture[_]] = + super.munitFixtures ++ List(targetroot) + + def checkOverrides( + options: TestOptions, + source: String, + extractSymbol: String, + expectedSymbols: List[String], + expectedCount: Int, + qualifiedClassName: String = "example.Parent" + ): Unit = { + test(options) { + val compiler = new TestCompiler(targetroot()) + val relativePath = qualifiedClassName.replace('.', '/') + ".java" + val input = Input.VirtualFile(relativePath, source) + val result = compiler.compileSemanticdb(List(input)) + val symtab = new Symtab(result.textDocument) + + val count = symtab.symbols.get(extractSymbol).getOverriddenSymbolsCount + val syms = symtab + .symbols + .get(extractSymbol) + .getOverriddenSymbolsList + .toArray(new Array[String](count)) + assertEquals(count, expectedCount) + syms + .zipWithIndex + .foreach { case (str, i) => + assertEquals(str, expectedSymbols(i)) + } + } + } + + checkOverrides( + "same file", + """package example; + | + |class Parent { + | public void stuff() {} + | + | class Child extends Parent { + | @Override + | public void stuff() {} + | } + |} + |""".stripMargin, + "example/Parent#Child#stuff().", + List("example/Parent#stuff()."), + 1 + ) + + checkOverrides( + "external override", + """package example; + | + |class Parent { + | @Override + | public String toString() { return ""; } + |} + |""".stripMargin, + "example/Parent#toString().", + List("java/lang/Object#toString()."), + 1 + ) + + checkOverrides( + "implement interface", + """package example; + | + |class Parent { + | interface Test { + | public void stuff(); + | } + | + | class Child implements Test { + | @Override + | public void stuff() {} + | } + |} + |""".stripMargin, + "example/Parent#Child#stuff().", + List("example/Parent#Test#stuff()."), + 1 + ) + + checkOverrides( + "type params", + """package example; + | + |class Parent { + | interface Haha { + | void add(T elem); + | } + | class IntHaha implements Haha { + | void add(Integer elem) {} + | } + |} + |""".stripMargin, + "example/Parent#IntHaha#add().", + List("example/Parent#Haha#add()."), + 1 + ) + + checkOverrides( + "multiple", + """package example; + | + |class Parent { + | @Override + | public String toString() { return ""; } + | + | class Child extends Parent { + | @Override + | public String toString() { return ""; } + | } + |} + |""".stripMargin, + "example/Parent#Child#toString().", + List("example/Parent#toString().", "java/lang/Object#toString()."), + 2 + ) + + checkOverrides( + "abstract", + """package example; + | + |abstract class Parent { + | public abstract void stuff(); + | + | class Child extends Parent { + | @Override + | public void stuff() {} + | } + |} + |""".stripMargin, + "example/Parent#Child#stuff().", + List("example/Parent#stuff()."), + 1 + ) +} From a393f405d9a5d7e41a8a228886097b8f754d459d Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Tue, 20 Apr 2021 21:10:31 +0100 Subject: [PATCH 4/5] link referenceResult of overridden symbol to range of overriding symbol --- .../java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java index fcf0abf6..e9431a9b 100644 --- a/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java +++ b/lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdb.java @@ -144,6 +144,8 @@ private Integer processDocument( String overriddenSymbol = symbolInformation.getOverriddenSymbols(i); ResultIds overriddenIds = results.getOrInsertResultSet(overriddenSymbol); overriddenReferenceResultIds[i] = overriddenIds.referenceResult; + writer.emitReferenceResultsItemEdge( + overriddenIds.referenceResult, new int[] {rangeId}, doc.id); } writer.emitReferenceResultsItemEdge( ids.referenceResult, overriddenReferenceResultIds, doc.id); From 38734560699be0e540d8f71287d95df20df363ec Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Mon, 26 Apr 2021 13:41:04 +0100 Subject: [PATCH 5/5] assertNoDiff for overridden symbols list --- .../src/test/scala/tests/OverridesSuite.scala | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/tests/unit/src/test/scala/tests/OverridesSuite.scala b/tests/unit/src/test/scala/tests/OverridesSuite.scala index fdb5c625..e3f2886a 100644 --- a/tests/unit/src/test/scala/tests/OverridesSuite.scala +++ b/tests/unit/src/test/scala/tests/OverridesSuite.scala @@ -1,5 +1,7 @@ package tests +import java.util.stream.Collectors + import scala.meta.Input import com.sourcegraph.lsif_semanticdb.Symtab @@ -17,29 +19,23 @@ class OverridesSuite extends FunSuite with TempDirectories { options: TestOptions, source: String, extractSymbol: String, - expectedSymbols: List[String], - expectedCount: Int, - qualifiedClassName: String = "example.Parent" + expectedSymbols: String* ): Unit = { test(options) { val compiler = new TestCompiler(targetroot()) - val relativePath = qualifiedClassName.replace('.', '/') + ".java" + val relativePath = "example.Parent".replace('.', '/') + ".java" val input = Input.VirtualFile(relativePath, source) val result = compiler.compileSemanticdb(List(input)) val symtab = new Symtab(result.textDocument) - val count = symtab.symbols.get(extractSymbol).getOverriddenSymbolsCount + val expectedSyms = expectedSymbols.mkString("\n") val syms = symtab .symbols .get(extractSymbol) .getOverriddenSymbolsList - .toArray(new Array[String](count)) - assertEquals(count, expectedCount) - syms - .zipWithIndex - .foreach { case (str, i) => - assertEquals(str, expectedSymbols(i)) - } + .stream + .collect(Collectors.joining("\n")) + assertNoDiff(expectedSyms, syms) } } @@ -57,8 +53,7 @@ class OverridesSuite extends FunSuite with TempDirectories { |} |""".stripMargin, "example/Parent#Child#stuff().", - List("example/Parent#stuff()."), - 1 + "example/Parent#stuff()." ) checkOverrides( @@ -71,8 +66,7 @@ class OverridesSuite extends FunSuite with TempDirectories { |} |""".stripMargin, "example/Parent#toString().", - List("java/lang/Object#toString()."), - 1 + "java/lang/Object#toString()." ) checkOverrides( @@ -91,8 +85,7 @@ class OverridesSuite extends FunSuite with TempDirectories { |} |""".stripMargin, "example/Parent#Child#stuff().", - List("example/Parent#Test#stuff()."), - 1 + "example/Parent#Test#stuff()." ) checkOverrides( @@ -109,8 +102,7 @@ class OverridesSuite extends FunSuite with TempDirectories { |} |""".stripMargin, "example/Parent#IntHaha#add().", - List("example/Parent#Haha#add()."), - 1 + "example/Parent#Haha#add()." ) checkOverrides( @@ -128,8 +120,9 @@ class OverridesSuite extends FunSuite with TempDirectories { |} |""".stripMargin, "example/Parent#Child#toString().", - List("example/Parent#toString().", "java/lang/Object#toString()."), - 2 + """example/Parent#toString(). + |java/lang/Object#toString(). + |""".stripMargin ) checkOverrides( @@ -146,7 +139,6 @@ class OverridesSuite extends FunSuite with TempDirectories { |} |""".stripMargin, "example/Parent#Child#stuff().", - List("example/Parent#stuff()."), - 1 + "example/Parent#stuff()." ) }