diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 808c2bef5..b94c20909 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -31,8 +31,8 @@ If you'd rather install tools manually, you'll need at least:
These are the main components of the project.
-- `semanticdb-javac/src/main/java`: the Java compiler plugin that creates
- SemanticDB files.
+- `semanticdb-javac/src/main/java`: the Java compiler plugin that emits
+ SCIP shard files.
- `tests/minimized`: minimized Java source files that reproduce interesting test
cases.
- `tests/unit`: fast running unit tests that are helpful for local edit-and-test
diff --git a/build.sbt b/build.sbt
index 9430dd380..285154984 100644
--- a/build.sbt
+++ b/build.sbt
@@ -75,9 +75,7 @@ lazy val semanticdb = project
.in(file("semanticdb-java"))
.settings(
moduleName := "semanticdb-java",
- javaOnlySettings,
- (Compile / PB.targets) :=
- Seq(PB.gens.java(V.protobuf) -> (Compile / sourceManaged).value)
+ javaOnlySettings
)
lazy val agent = project
@@ -169,7 +167,7 @@ lazy val javacPlugin = project
.inAll
)
)
- .dependsOn(semanticdb)
+ .dependsOn(semanticdb, scipProto)
lazy val scipProto = project
.in(file("scip-java-proto"))
@@ -440,13 +438,15 @@ lazy val semanticdbKotlinc = project
Attributed.blank(dir)
}
)
+ .dependsOn(scipProto)
// `semanticdbKotlincMinimized` mirrors the (still-present) Gradle build at
// semanticdb-kotlinc/minimized/build.gradle.kts. It compiles a small set of
// Kotlin and Java fixtures with the assembled `semanticdbKotlinc` plugin
-// attached to kotlinc/javac, producing *.semanticdb files under
-// target/semanticdb-targetroot/ which are then converted to SCIP and rendered
-// as the human-readable golden snapshots by the `snapshots` task.
+// attached to kotlinc/javac, producing *.scip shard files under
+// target/semanticdb-targetroot/ which are then aggregated into a single SCIP
+// index and rendered as the human-readable golden snapshots by the
+// `snapshots` task.
lazy val semanticdbKotlincMinimized = project
.in(file("semanticdb-kotlinc/minimized"))
.enablePlugins(KotlinPlugin)
@@ -510,7 +510,7 @@ lazy val semanticdbKotlincMinimized = project
// ----- snapshots regeneration task -----
// Invokes `com.sourcegraph.scip_java.ScipJava.main` twice in the cli JVM
// (forked — ScipJava.main calls System.exit on failure). First pass
- // converts the *.semanticdb files under target/semanticdb-targetroot/
+ // aggregates the *.scip shard files under target/semanticdb-targetroot/
// into an index.scip; second pass renders that index as the human-readable
// golden snapshots.
//
@@ -524,7 +524,10 @@ lazy val semanticdbKotlincMinimized = project
val snapDir =
(baseDirectory.value / "src" / "generatedSnapshots" / "resources")
.getAbsolutePath
- val scipOut = s"$tgtRoot/index.scip"
+ // Place the aggregated `index.scip` outside the shard-scanned
+ // targetroot so a subsequent run doesn't re-ingest it as a shard.
+ val scipOut = (target.value / "scip-index" / "index.scip")
+ .getAbsolutePath
val mainCls = "com.sourcegraph.scip_java.ScipJava"
Def.sequential(
Compile / compile,
@@ -532,7 +535,7 @@ lazy val semanticdbKotlincMinimized = project
s" $mainCls index-semanticdb --no-emit-inverse-relationships --cwd $srcRoot --output $scipOut $tgtRoot"
),
(cli / Compile / runMain).toTask(
- s" $mainCls snapshot --cwd $srcRoot --output $snapDir $tgtRoot"
+ s" $mainCls snapshot --cwd $srcRoot --output $snapDir ${file(scipOut).getParentFile.getAbsolutePath}"
)
)
}
@@ -695,6 +698,11 @@ lazy val fatjarPackageSettings = List[Def.Setting[_]](
MergeStrategy.discard
case PathList("META-INF", "versions", "9", "module-info.class") =>
MergeStrategy.discard
+ // Bazel BUILD files live next to *.proto sources in our subprojects; they are
+ // not needed at runtime and would conflict when multiple proto modules are
+ // merged into the same fat jar.
+ case PathList("BUILD") =>
+ MergeStrategy.discard
case x =>
val oldStrategy = (assembly / assemblyMergeStrategy).value
oldStrategy(x)
diff --git a/docs/design.md b/docs/design.md
index af79ca5f6..853fc6f25 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -5,10 +5,9 @@ title: Design
This project is implemented as a
[Java compiler plugin](https://docs.oracle.com/en/java/javase/11/docs/api/jdk.compiler/com/sun/source/util/Plugin.html)
-that generates one
-[SemanticDB](https://scalameta.org/docs/semanticdb/specification.html) file for
-every `*.java` source file. After compilation completes, the SemanticDB files
-are processed to produce SCIP.
+that emits one [SCIP](https://github.com/sourcegraph/scip) shard file for every
+`*.java` source file. After compilation completes, the per-file SCIP shards are
+aggregated into a single SCIP index.
### Why Java compiler plugin?
@@ -24,24 +23,3 @@ There are several benefits to implementing scip-java as a compiler plugin:
tool, we minimize the risk of diverging from the CI build environment such as
installed system dependencies, custom compiler options and custom annotation
processors.
-
-### Why SemanticDB?
-
-SemanticDB is Protobuf schema for information about symbols and types in Java
-programs and other languages. There are several benefits to using SemanticDB as
-an intermediary representation for SCIP:
-
-- **Simplicity**: It's easy to translate a single Java source file into a single
- SemanticDB file inside a compiler plugin. It's more complicated to produce
- SCIP because compiler plugins does not have access to a project-wide context,
- which is necessary to produce accurate definitions and hovers in multi-module
- projects with external library dependencies.
-- **Performance**: SemanticDB is fast to write and read. Each compilation unit
- can be processed independently to keep memory usage low. The final conversion
- from SemanticDB to SCIP can be safely parallelized.
-- **Cross-repository**: Compiler plugins have access to both source code and the
- classpath (compiled bytecode of upstream dependencies). SemanticDB has been
- designed so that it's also possible to generate spec-compliant symbols from
- the classpath alone (no source code) and from the syntax tree of an individual
- source file (no classpath). This flexibility will be helpful for scip-java in
- the future to unblock cross-repository navigation.
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 93d896a09..9e1a3515a 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -351,10 +351,10 @@ Next, run the following command to generate the SCIP index (`index.scip`).
```
bazel run @scip_java//scip-semanticdb:bazel -- --sourceroot $PWD
-# (optional) Validate that SemanticDB files were generated.
+# (optional) Validate that SCIP shard files were generated.
# The command below works for the `examples/bazel-example` directory in the sourcegraph/scip-java repository.
-❯ jar tf bazel-bin/src/main/java/example/libexample.jar | grep semanticdb$
-META-INF/semanticdb/src/main/java/example/Example.java.semanticdb
+❯ jar tf bazel-bin/src/main/java/example/libexample.jar | grep scip$
+META-INF/scip/src/main/java/example/Example.java.scip
```
Finally, run the following commands to upload the SCIP index to Sourcegraph.
diff --git a/docs/manual-configuration.md b/docs/manual-configuration.md
index 49e3597d5..98c473fb4 100644
--- a/docs/manual-configuration.md
+++ b/docs/manual-configuration.md
@@ -12,10 +12,9 @@ fails.
Indexing a codebase consists of two independent phases:
-- Compile the codebase with the SemanticDB compiler plugin.
-- Generate SCIP index from SemanticDB files.
-
-
+- Compile the codebase with the SemanticDB compiler plugin, which writes one
+ SCIP shard per Java source file.
+- Aggregate the SCIP shards into a single SCIP index.
The first phase can be complicated to configure and it can take a while to run.
The second phase is quite simple to configure and it usually runs very fast.
@@ -63,7 +62,7 @@ compiler plugin. To do this you need to explicitly configure two directories:
It's important that all of the source files that should be index live under
this directory.
- `-targetroot:PATH`: the absolute path to the directory where to generate
- SemanticDB file. This directory can be anywhere on your file system.
+ SCIP shard files. This directory can be anywhere on your file system.
Alternatively, pass in `-targetroot:javac-classes-directory` for the plugin to
automatically use the `javac` output directory.
@@ -112,13 +111,13 @@ examples:
- Maven: `mvn clean verify -DskipTests`
- Bazel: `bazel build //...`
-If everything went well, you should have a lot of `*.semanticdb` files in the
+If everything went well, you should have a lot of `*.scip` shard files in the
targetroot directory.
```
❯ find $TARGETROOT -type f
-build/semanticdb-targetroot/META-INF/semanticdb/j11/src/test/java/example/ExampleTest.java.semanticdb
-build/semanticdb-targetroot/META-INF/semanticdb/j11/src/main/java/example/Example.java.semanticdb
+build/semanticdb-targetroot/META-INF/scip/j11/src/test/java/example/ExampleTest.java.scip
+build/semanticdb-targetroot/META-INF/scip/j11/src/main/java/example/Example.java.scip
...
```
@@ -198,13 +197,13 @@ Which allows you to invoke it by simply running `mvn sourcegraph:sourcegraphDepe
Cross-repository navigation is a feature that allows "goto definition" and "find
references" to show results from multiple repositories.
-## Step 5: Generate SCIP index from SemanticDB files
+## Step 5: Aggregate SCIP shards into a single SCIP index
First, install the `scip-java` command-line tool according to the instructions
in the [getting started guide](getting-started.md).
-Next, run the `scip-java index-semanticdb` command to convert SemanticDB files
-into SCIP.
+Next, run the `scip-java index-semanticdb` command to aggregate the per-file
+SCIP shards into a single SCIP index.
```sh
❯ scip-java index-semanticdb $TARGETROOT
diff --git a/scip-java/src/main/scala/com/sourcegraph/scip_java/buildtools/ScipBuildTool.scala b/scip-java/src/main/scala/com/sourcegraph/scip_java/buildtools/ScipBuildTool.scala
index 7656a8dd0..3bcb1bae6 100644
--- a/scip-java/src/main/scala/com/sourcegraph/scip_java/buildtools/ScipBuildTool.scala
+++ b/scip-java/src/main/scala/com/sourcegraph/scip_java/buildtools/ScipBuildTool.scala
@@ -206,7 +206,7 @@ class ScipBuildTool(index: IndexCommand) extends BuildTool("SCIP", index) {
.app
.reporter
.info(
- "Some SemanticDB files got generated even if there were compile errors. " +
+ "Some SCIP shard files got generated even if there were compile errors. " +
"In most cases, this means that scip-java managed to index everything " +
"except the locations that had compile errors and you can ignore the compile errors."
)
diff --git a/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexCommand.scala b/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexCommand.scala
index 566fc0c0e..04e962280 100644
--- a/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexCommand.scala
+++ b/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexCommand.scala
@@ -29,7 +29,7 @@ case class IndexCommand(
@Description("The path where to generate the SCIP index.")
output: Path = Paths.get("index.scip"),
@Description(
- "The directory where to generate SemanticDB files. " +
+ "The directory where to generate SCIP shard files. " +
"Defaults to a build-specific path. " +
"For example, the default value for Gradle is 'build/semanticdb-targetroot' and for Maven it's 'target/semanticdb-targetroot'"
)
diff --git a/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexSemanticdbCommand.scala b/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexSemanticdbCommand.scala
index 194c1a85c..999b2c9b7 100644
--- a/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexSemanticdbCommand.scala
+++ b/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/IndexSemanticdbCommand.scala
@@ -12,8 +12,8 @@ import com.sourcegraph.scip_java.BuildInfo
import com.sourcegraph.scip_java.buildtools.ClasspathEntry
import com.sourcegraph.scip_semanticdb.ConsoleScipSemanticdbReporter
import com.sourcegraph.scip_semanticdb.ScipOutputFormat
-import com.sourcegraph.scip_semanticdb.ScipSemanticdb
import com.sourcegraph.scip_semanticdb.ScipSemanticdbOptions
+import com.sourcegraph.scip_semanticdb.ScipShardAggregator
import moped.annotations._
import moped.cli.Application
import moped.cli.Command
@@ -21,7 +21,7 @@ import moped.cli.CommandParser
import ujson.Arr
import ujson.Obj
-@Description("Converts SemanticDB files into a single SCIP index file.")
+@Description("Aggregates SCIP shard files into a single SCIP index file.")
@Usage("scip-java index-semanticdb [OPTIONS ...] [POSITIONAL ARGUMENTS ...]")
@ExampleUsage(
"scip-java index-semanticdb --out=myindex.scip my/targetroot1 my/targetroot2"
@@ -30,10 +30,10 @@ import ujson.Obj
final case class IndexSemanticdbCommand(
@Description("The name of the output file.")
output: Path = Paths.get("index.scip"),
- @Description("Whether to process the SemanticDB files in parallel")
+ @Description("Whether to process the SCIP shard files in parallel")
parallel: Boolean = true,
@Description(
- "Whether to infer the location of SemanticDB files based as produced by Bazel"
+ "Whether to infer the location of SCIP shard files based as produced by Bazel"
)
bazel: Boolean = true,
@Description(
@@ -44,7 +44,7 @@ final case class IndexSemanticdbCommand(
@Description("URL to a PackageHub instance")
@Hidden
packagehub: Option[String] = None,
- @Description("Directories that contain SemanticDB files.")
+ @Description("Directories that contain SCIP shard files.")
@PositionalArguments()
targetroot: List[Path] = Nil,
@Description(
@@ -108,7 +108,7 @@ final case class IndexSemanticdbCommand(
allowEmptyIndex,
allowExportingGlobalSymbolsFromDirectoryEntries
)
- ScipSemanticdb.run(options)
+ ScipShardAggregator.run(options)
postPackages(packages)
if (!app.reporter.hasErrors()) {
app.info(options.output.toString)
diff --git a/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/SnapshotCommand.scala b/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/SnapshotCommand.scala
index 6b3425739..9ac166cf6 100644
--- a/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/SnapshotCommand.scala
+++ b/scip-java/src/main/scala/com/sourcegraph/scip_java/commands/SnapshotCommand.scala
@@ -51,31 +51,37 @@ case class SnapshotCommand(
attrs: BasicFileAttributes
): FileVisitResult = {
if (scipPattern.matches(file)) {
- foundScipFile = true
val index = Scip.Index.parseFrom(Files.readAllBytes(file))
- val root = URI.create(index.getMetadata.getProjectRoot)
- index
- .getDocumentsList
- .asScala
- .foreach { doc =>
- val sourcepath = Paths.get(root.resolve(doc.getRelativePath))
- val source =
- new String(
- Files.readAllBytes(sourcepath),
- StandardCharsets.UTF_8
+ // Skip per-source shards emitted by the compiler plugin (those don't have a
+ // project_root). The aggregator produces a single top-level index file that
+ // carries the project_root and is the canonical input for snapshot rendering.
+ val rawProjectRoot = index.getMetadata.getProjectRoot
+ if (rawProjectRoot.nonEmpty) {
+ foundScipFile = true
+ val projectRoot = URI.create(rawProjectRoot)
+ index
+ .getDocumentsList
+ .asScala
+ .foreach { doc =>
+ val sourcepath = Paths.get(projectRoot.resolve(doc.getRelativePath))
+ val source =
+ new String(
+ Files.readAllBytes(sourcepath),
+ StandardCharsets.UTF_8
+ )
+ val document = ScipPrinters.printTextDocument(
+ doc,
+ source,
+ CommentSyntax.default
)
- val document = ScipPrinters.printTextDocument(
- doc,
- source,
- CommentSyntax.default
- )
- val snapshotOutput = output.resolve(doc.getRelativePath)
- Files.createDirectories(snapshotOutput.getParent)
- Files.write(
- snapshotOutput,
- document.getBytes(StandardCharsets.UTF_8)
- )
- }
+ val snapshotOutput = output.resolve(doc.getRelativePath)
+ Files.createDirectories(snapshotOutput.getParent)
+ Files.write(
+ snapshotOutput,
+ document.getBytes(StandardCharsets.UTF_8)
+ )
+ }
+ }
}
super.visitFile(file, attrs)
}
diff --git a/scip-semanticdb/BUILD b/scip-semanticdb/BUILD
index 6c2b8b5a0..37565d9f0 100644
--- a/scip-semanticdb/BUILD
+++ b/scip-semanticdb/BUILD
@@ -20,7 +20,6 @@ java_library(
":all_java_proto",
"//scip-java-proto/src/main/protobuf:scip_java_proto",
"//semanticdb-java",
- "//semanticdb-java/src/main/protobuf:semanticdb_java_proto",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_protobuf_protobuf_java",
"@maven//:com_google_protobuf_protobuf_java_util",
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/BazelBuildTool.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/BazelBuildTool.java
index e5fb161f3..10428b931 100644
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/BazelBuildTool.java
+++ b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/BazelBuildTool.java
@@ -66,7 +66,7 @@ public boolean hasErrors() {
/* allowEmptyIndex */ true,
/* indexDirectoryEntries */ false // because Bazel only compiles to jar files.
);
- ScipSemanticdb.run(scipOptions);
+ ScipShardAggregator.run(scipOptions);
if (!scipOptions.reporter.hasErrors()) {
System.out.println("done: " + scipOptions.output);
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/RangeComparator.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/RangeComparator.java
deleted file mode 100644
index aa16a5af2..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/RangeComparator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb.Range;
-
-/**
- * Comparator that sorts SemanticDB ranges by appearance in the document.
- *
- *
We can't guarantee ordering of SymbolOccurrence in SemanticDB payloads so it's good to sort
- * them before processing.
- */
-public class RangeComparator implements java.util.Comparator {
-
- @Override
- public int compare(Range r1, Range r2) {
- int byStartLine = Integer.compare(r1.getStartLine(), r2.getStartLine());
- if (byStartLine != 0) {
- return byStartLine;
- }
- int byStartCharacter = Integer.compare(r1.getStartCharacter(), r2.getStartCharacter());
- if (byStartCharacter != 0) {
- return byStartCharacter;
- }
- int byEndLine = Integer.compare(r1.getEndLine(), r2.getEndLine());
- if (byEndLine != 0) {
- return byEndLine;
- }
- return Integer.compare(r1.getEndCharacter(), r2.getEndCharacter());
- }
-}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipSemanticdb.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipSemanticdb.java
deleted file mode 100644
index 789a9afef..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipSemanticdb.java
+++ /dev/null
@@ -1,427 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.google.protobuf.CodedInputStream;
-import com.sourcegraph.semanticdb_javac.Semanticdb;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolInformation;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolInformation.Kind;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolInformation.Property;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolOccurrence;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolOccurrence.Role;
-import com.sourcegraph.semanticdb_javac.SemanticdbSymbols;
-import com.sourcegraph.Scip;
-
-import java.io.IOException;
-import java.net.URI;
-import java.nio.file.*;
-import java.util.*;
-
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-/** The core logic that converts SemanticDB into SCIP. */
-public class ScipSemanticdb {
- private final ScipWriter writer;
- private final ScipSemanticdbOptions options;
-
- public ScipSemanticdb(ScipWriter writer, ScipSemanticdbOptions options) {
- this.writer = writer;
- this.options = options;
- }
-
- public static void run(ScipSemanticdbOptions options) throws IOException {
- ScipWriter writer = new ScipWriter(options);
- new ScipSemanticdb(writer, options).run();
- }
-
- private void run() throws IOException {
- PackageTable packages = new PackageTable(options);
- List files = SemanticdbWalker.findSemanticdbFiles(options);
- Collections.sort(files);
- if (options.reporter.hasErrors()) return;
- if (files.isEmpty() && !options.allowEmptyIndex) {
- options.reporter.error(
- "No SemanticDB files found. "
- + "This typically means that `scip-java` is unable to automatically "
- + "index this codebase. If you are using Gradle or Maven, please report an issue to "
- + "https://github.com/sourcegraph/scip-java and include steps to reproduce. "
- + "If you are using a different build tool, make sure that you have followed all "
- + "of the steps from https://sourcegraph.github.io/scip-java/docs/manual-configuration.html");
- return;
- }
- options.reporter.startProcessing(files.size());
- runTyped(files, packages);
- writer.build();
- options.reporter.endProcessing();
- }
-
- private void runTyped(List files, PackageTable packages) {
- writer.emitTyped(typedMetadata());
- InverseReferenceRelationships references = inverseReferenceRelationships(files);
- filesStream(files).forEach(document -> processTypedDocument(document, packages, references));
- }
-
- private String typedSymbol(String symbol, Package pkg) {
- if (symbol.isEmpty()) {
- return "";
- }
- if (symbol.startsWith("local")) {
- return "local " + symbol.substring("local".length());
- }
- return "semanticdb maven " + pkg.repoName() + " " + pkg.version() + " " + symbol;
- }
-
- private static Scip.SymbolInformation.Kind scipKind(SymbolInformation info) {
- Kind kind = info.getKind();
- int properties = info.getProperties();
- boolean isStatic = (properties & Property.STATIC_VALUE) > 0;
- boolean isAbstract = (properties & Property.ABSTRACT_VALUE) > 0;
- boolean isEnum = (properties & Property.ENUM_VALUE) > 0;
-
- switch (kind) {
- case CLASS:
- if (isEnum) {
- return Scip.SymbolInformation.Kind.Enum;
- } else {
- return Scip.SymbolInformation.Kind.Class;
- }
- case CONSTRUCTOR:
- return Scip.SymbolInformation.Kind.Constructor;
- case FIELD:
- if (isStatic) {
- return Scip.SymbolInformation.Kind.StaticField;
- } else {
- return Scip.SymbolInformation.Kind.Field;
- }
- case INTERFACE:
- return Scip.SymbolInformation.Kind.Interface;
- case LOCAL:
- if (isStatic) {
- return Scip.SymbolInformation.Kind.StaticVariable;
- } else {
- return Scip.SymbolInformation.Kind.Variable;
- }
- case MACRO:
- return Scip.SymbolInformation.Kind.Macro;
- case METHOD:
- if (isStatic) {
- return Scip.SymbolInformation.Kind.StaticMethod;
- } else if (isAbstract) {
- return Scip.SymbolInformation.Kind.AbstractMethod;
- } else {
- return Scip.SymbolInformation.Kind.Method;
- }
- case OBJECT:
- return Scip.SymbolInformation.Kind.Object;
- case PACKAGE:
- return Scip.SymbolInformation.Kind.Package;
- case PACKAGE_OBJECT:
- return Scip.SymbolInformation.Kind.PackageObject;
- case PARAMETER:
- return Scip.SymbolInformation.Kind.Parameter;
- case SELF_PARAMETER:
- return Scip.SymbolInformation.Kind.SelfParameter;
- case TRAIT:
- return Scip.SymbolInformation.Kind.Trait;
- case TYPE:
- if (isEnum) {
- return Scip.SymbolInformation.Kind.Enum;
- } else {
- return Scip.SymbolInformation.Kind.Type;
- }
- case TYPE_PARAMETER:
- return Scip.SymbolInformation.Kind.TypeParameter;
- case UNKNOWN_KIND:
- return Scip.SymbolInformation.Kind.UnspecifiedKind;
- }
-
- return Scip.SymbolInformation.Kind.UnspecifiedKind;
- }
-
- public static boolean isDefinitionRole(Role role) {
- return role == Role.DEFINITION || role == Role.SYNTHETIC_DEFINITION;
- }
-
- private void processTypedDocument(
- Path path, PackageTable packages, InverseReferenceRelationships references) {
- for (ScipTextDocument doc : parseTextDocument(path).collect(Collectors.toList())) {
- if (doc.semanticdb.getOccurrencesCount() == 0) {
- continue;
- }
-
- Path absolutePath = Paths.get(URI.create(doc.semanticdb.getUri()));
- String relativePath =
- StreamSupport.stream(options.sourceroot.relativize(absolutePath).spliterator(), false)
- .map(p -> p.getFileName().toString())
- .collect(Collectors.joining("/"));
- Scip.Document.Builder tdoc = Scip.Document.newBuilder().setRelativePath(relativePath);
- for (SymbolOccurrence occ : doc.sortedSymbolOccurrences()) {
- if (occ.getSymbol().isEmpty()) {
- continue;
- }
- int role = 0;
- if (isDefinitionRole(occ.getRole())) {
- role |= Scip.SymbolRole.Definition_VALUE;
- }
- boolean isSingleLineRange = occ.getRange().getStartLine() == occ.getRange().getEndLine();
- Iterable range =
- isSingleLineRange
- ? Arrays.asList(
- occ.getRange().getStartLine(),
- occ.getRange().getStartCharacter(),
- occ.getRange().getEndCharacter())
- : Arrays.asList(
- occ.getRange().getStartLine(),
- occ.getRange().getStartCharacter(),
- occ.getRange().getEndLine(),
- occ.getRange().getEndCharacter());
- Package pkg = packages.packageForSymbol(occ.getSymbol()).orElse(Package.EMPTY);
- Scip.Occurrence.Builder occBuilder =
- Scip.Occurrence.newBuilder()
- .addAllRange(range)
- .setSymbol(typedSymbol(occ.getSymbol(), pkg))
- .setSymbolRoles(role);
- // Add enclosing_range if it exists
- if (occ.hasEnclosingRange()) {
- Semanticdb.Range enclosingRange = occ.getEnclosingRange();
- boolean isEnclosingSingleLine =
- enclosingRange.getStartLine() == enclosingRange.getEndLine();
- Iterable enclosingRangeInts =
- isEnclosingSingleLine
- ? Arrays.asList(
- enclosingRange.getStartLine(),
- enclosingRange.getStartCharacter(),
- enclosingRange.getEndCharacter())
- : Arrays.asList(
- enclosingRange.getStartLine(),
- enclosingRange.getStartCharacter(),
- enclosingRange.getEndLine(),
- enclosingRange.getEndCharacter());
- occBuilder.addAllEnclosingRange(enclosingRangeInts);
- }
- tdoc.addOccurrences(occBuilder);
- }
- Symtab symtab = new Symtab(doc.semanticdb);
- for (SymbolInformation info : doc.semanticdb.getSymbolsList()) {
- if (info.getSymbol().isEmpty()) {
- continue;
- }
- Package pkg = packages.packageForSymbol(info.getSymbol()).orElse(Package.EMPTY);
- Scip.SymbolInformation.Builder scipInfo =
- Scip.SymbolInformation.newBuilder().setSymbol(typedSymbol(info.getSymbol(), pkg));
-
- scipInfo.setDisplayName(info.getDisplayName());
- if (!info.getEnclosingSymbol().isEmpty()) {
- scipInfo.setEnclosingSymbol(typedSymbol(info.getEnclosingSymbol(), pkg));
- }
-
- scipInfo.setKind(scipKind(info));
-
- // TODO: this can be removed once https://github.com/sourcegraph/sourcegraph/issues/50927 is
- // fixed.
- ArrayList inverseReferences = references.map.get(info.getSymbol());
- if (inverseReferences != null) {
- for (String inverseReference : inverseReferences) {
- Package inverseReferencePkg =
- packages.packageForSymbol(inverseReference).orElse(Package.EMPTY);
- scipInfo.addRelationships(
- Scip.Relationship.newBuilder()
- .setSymbol(typedSymbol(inverseReference, inverseReferencePkg))
- .setIsImplementation(true)
- .setIsReference(true));
- }
- }
-
- for (int i = 0; i < info.getDefinitionRelationshipsCount(); i++) {
- String definitionSymbol = info.getDefinitionRelationships(i);
- if (definitionSymbol.isEmpty()) {
- continue;
- }
- Package definitionSymbolPkg =
- packages.packageForSymbol(definitionSymbol).orElse(Package.EMPTY);
- SymbolInformation definitionInfo = symtab.symbols.get(definitionSymbol);
-
- scipInfo.addRelationships(
- Scip.Relationship.newBuilder()
- .setSymbol(typedSymbol(definitionSymbol, definitionSymbolPkg))
- .setIsDefinition(true)
- .setIsReference(
- definitionInfo != null
- && definitionInfo.getDisplayName().equals(info.getDisplayName())
- && supportsReferenceRelationship(info)));
- }
-
- for (int i = 0; i < info.getOverriddenSymbolsCount(); i++) {
- String overriddenSymbol = info.getOverriddenSymbols(i);
- if (overriddenSymbol.isEmpty()) {
- continue;
- }
- if (isIgnoredOverriddenSymbol(overriddenSymbol)) {
- continue;
- }
- Package overriddenSymbolPkg =
- packages.packageForSymbol(overriddenSymbol).orElse(Package.EMPTY);
- scipInfo.addRelationships(
- Scip.Relationship.newBuilder()
- .setSymbol(typedSymbol(overriddenSymbol, overriddenSymbolPkg))
- .setIsImplementation(true)
- .setIsReference(supportsReferenceRelationship(info)));
- }
- if (info.hasSignature()) {
- String language =
- doc.semanticdb.getLanguage().toString().toLowerCase(Locale.ROOT).intern();
- String signature = new SignatureFormatter(info, symtab).formatSymbol();
- Scip.Document.Builder signatureDocumentation =
- Scip.Document.newBuilder()
- .setRelativePath(relativePath)
- .setLanguage(language)
- .setText(signature);
- scipInfo.setSignatureDocumentation(signatureDocumentation);
- }
- String documentation = info.getDocumentation().getMessage();
- if (!documentation.isEmpty()) {
- scipInfo.addDocumentation(documentation);
- }
- tdoc.addSymbols(scipInfo);
- }
- writer.emitTyped(Scip.Index.newBuilder().addDocuments(tdoc).build());
- }
- }
-
- private Scip.Index typedMetadata() {
- return Scip.Index.newBuilder()
- .setMetadata(
- Scip.Metadata.newBuilder()
- .setVersion(Scip.ProtocolVersion.UnspecifiedProtocolVersion)
- .setProjectRoot(options.sourceroot.toUri().toString())
- .setTextDocumentEncoding(Scip.TextEncoding.UTF8)
- .setToolInfo(
- Scip.ToolInfo.newBuilder()
- .setName(options.toolInfo.getName())
- .setVersion(options.toolInfo.getVersion())
- .addAllArguments(options.toolInfo.getArgumentsList())))
- .build();
- }
-
- private Stream filesStream(List files) {
- return options.parallel ? files.parallelStream() : files.stream();
- }
-
- private static class InverseReferenceRelationships {
- public final Map> map;
-
- private InverseReferenceRelationships(Map> map) {
- this.map = map;
- }
- }
-
- private InverseReferenceRelationships inverseReferenceRelationships(List files) {
- if (!options.emitInverseRelationships) {
- return new InverseReferenceRelationships(Collections.emptyMap());
- }
- return new InverseReferenceRelationships(
- filesStream(files)
- .flatMap(this::parseTextDocument)
- .flatMap(this::referenceRelationships)
- .collect(
- Collectors.groupingBy(
- SymbolRelationship::getTo,
- Collectors.mapping(
- SymbolRelationship::getFrom, Collectors.toCollection(ArrayList::new)))));
- }
-
- private Stream referenceRelationships(ScipTextDocument document) {
- ArrayList relationships = new ArrayList<>();
- for (int i = 0; i < document.semanticdb.getSymbolsCount(); i++) {
- SymbolInformation info = document.semanticdb.getSymbols(i);
- if (!supportsReferenceRelationship(info)) {
- continue;
- }
- if (info.getSymbol().isEmpty() || SemanticdbSymbols.isLocal(info.getSymbol())) {
- continue;
- }
- for (int j = 0; j < info.getOverriddenSymbolsCount(); j++) {
- String overriddenSymbol = info.getOverriddenSymbols(j);
- if (SemanticdbSymbols.isLocal(overriddenSymbol)) {
- continue;
- }
- relationships.add(new SymbolRelationship(info.getSymbol(), overriddenSymbol));
- }
- }
- return relationships.stream();
- }
-
- private static boolean supportsReferenceRelationship(SymbolInformation info) {
- switch (info.getKind()) {
- case INTERFACE:
- case TYPE:
- case CLASS:
- case OBJECT:
- case PACKAGE_OBJECT:
- return false;
- default:
- return true;
- }
- }
-
- private Stream parseTextDocument(Path semanticdbPath) {
- try {
- return textDocumentsParseFrom(semanticdbPath).getDocumentsList().stream()
- .filter(sdb -> !sdb.getOccurrencesList().isEmpty())
- .map(sdb -> new ScipTextDocument(semanticdbPath, sdb, options.sourceroot));
- } catch (IOException e) {
- options.reporter.error("invalid protobuf: " + semanticdbPath);
- options.reporter.error(e);
- return Stream.empty();
- }
- }
-
- private static PathMatcher jarPattern = FileSystems.getDefault().getPathMatcher("glob:**.jar");
-
- private Semanticdb.TextDocuments textDocumentsParseFrom(Path semanticdbPath) throws IOException {
- if (jarPattern.matches(semanticdbPath)) {
- return textDocumentsParseJarFile(semanticdbPath);
- }
- return textDocumentsParseFromBytes(Files.readAllBytes(semanticdbPath));
- }
-
- private Semanticdb.TextDocuments textDocumentsParseJarFile(Path jarFile) throws IOException {
- Semanticdb.TextDocuments.Builder result = Semanticdb.TextDocuments.newBuilder();
- try (JarFile file = new JarFile(jarFile.toFile())) {
- Enumeration entries = file.entries();
- while (entries.hasMoreElements()) {
- JarEntry element = entries.nextElement();
- if (element.getName().endsWith(".semanticdb")) {
- byte[] bytes = InputStreamBytes.readAll(file.getInputStream(element));
- result.addAllDocuments(textDocumentsParseFromBytes(bytes).getDocumentsList());
- }
- }
- }
- return result.build();
- }
-
- private Semanticdb.TextDocuments textDocumentsParseFromBytes(byte[] bytes) throws IOException {
- try {
- CodedInputStream in = CodedInputStream.newInstance(bytes);
- in.setRecursionLimit(1000);
- return Semanticdb.TextDocuments.parseFrom(in);
- } catch (NoSuchMethodError ignored) {
- // NOTE(olafur): For some reason, NoSuchMethodError gets thrown when running
- // `snapshots/run`
- // in the sbt build. I'm unable to reproduce the error in `snapshots/test` or
- // when running the
- // published version
- // of `scip-java index`.
- return Semanticdb.TextDocuments.parseFrom(bytes);
- }
- }
-
- private boolean isIgnoredOverriddenSymbol(String symbol) {
- // Skip java/lang/Object# and similar symbols from Scala since it's the parent
- // of all classes
- // making it noisy for "find implementations" results.
- return symbol.equals("java/lang/Object#");
- }
-}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipShardAggregator.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipShardAggregator.java
new file mode 100644
index 000000000..96458b331
--- /dev/null
+++ b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipShardAggregator.java
@@ -0,0 +1,317 @@
+package com.sourcegraph.scip_semanticdb;
+
+import com.google.protobuf.CodedInputStream;
+import com.sourcegraph.Scip;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Aggregates per-source {@code *.scip} shards into a single {@link Scip.Index}.
+ *
+ * Steps:
+ *
+ *
+ * - Walk all targetroots for {@code *.scip} shards (and {@code *.jar} files containing them).
+ *
- Parse each shard into a {@link Scip.Index} containing exactly one {@link Scip.Document}.
+ *
- Rewrite placeholder global symbols ({@code ". . . . "} prefix) into the final {@code
+ * "scip-java maven g a v ..."} form via {@link SymbolRewriter}.
+ *
- Deduplicate documents by {@code relative_path}, merging occurrences/symbols.
+ *
- Compute inverse {@code is_implementation+is_reference} relationships across the project.
+ *
- Emit the metadata block and all documents through {@link ScipWriter}.
+ *
+ */
+public final class ScipShardAggregator {
+
+ private final ScipWriter writer;
+ private final ScipSemanticdbOptions options;
+ private final SymbolRewriter rewriter;
+
+ public ScipShardAggregator(
+ ScipWriter writer, ScipSemanticdbOptions options, SymbolRewriter rewriter) {
+ this.writer = writer;
+ this.options = options;
+ this.rewriter = rewriter;
+ }
+
+ public static void run(ScipSemanticdbOptions options) throws IOException {
+ try (ScipWriter writer = new ScipWriter(options)) {
+ PackageTable packages = new PackageTable(options);
+ SymbolRewriter rewriter = new SymbolRewriter(packages);
+ new ScipShardAggregator(writer, options, rewriter).run();
+ writer.build();
+ }
+ }
+
+ private void run() throws IOException {
+ List shards = ScipShardWalker.findScipShards(options);
+ Collections.sort(shards);
+ if (options.reporter.hasErrors()) return;
+ if (shards.isEmpty() && !options.allowEmptyIndex) {
+ options.reporter.error(
+ "No SCIP shard files found. "
+ + "This typically means that `scip-java` is unable to automatically "
+ + "index this codebase. If you are using Gradle or Maven, please report an issue to "
+ + "https://github.com/sourcegraph/scip-java and include steps to reproduce. "
+ + "If you are using a different build tool, make sure that you have followed all "
+ + "of the steps from https://sourcegraph.github.io/scip-java/docs/manual-configuration.html");
+ return;
+ }
+ options.reporter.startProcessing(shards.size());
+ writer.emitTyped(metadata());
+
+ // Deduplicate documents by relative_path. We rewrite symbols as we go so all merging happens
+ // on final-form strings.
+ LinkedHashMap merged = new LinkedHashMap<>();
+ InverseReferenceRelationships inverse = new InverseReferenceRelationships();
+
+ for (Path shard : shards) {
+ try {
+ for (Scip.Index shardIndex : parseShard(shard)) {
+ for (Scip.Document doc : shardIndex.getDocumentsList()) {
+ Scip.Document rewritten = rewriteDocument(doc);
+ inverse.observe(rewritten);
+ Scip.Document.Builder existing = merged.get(rewritten.getRelativePath());
+ if (existing == null) {
+ merged.put(rewritten.getRelativePath(), rewritten.toBuilder());
+ } else {
+ mergeInto(existing, rewritten);
+ }
+ }
+ }
+ } catch (IOException e) {
+ options.reporter.error("invalid SCIP shard: " + shard);
+ options.reporter.error(e);
+ }
+ options.reporter.processedOneItem();
+ }
+
+ for (Scip.Document.Builder doc : merged.values()) {
+ Scip.Document withInverse = inverse.applyTo(doc.build());
+ writer.emitTyped(Scip.Index.newBuilder().addDocuments(withInverse).build());
+ }
+
+ options.reporter.endProcessing();
+ }
+
+ // --- shard parsing -------------------------------------------------------
+
+ private static final PathMatcher JAR_PATTERN =
+ FileSystems.getDefault().getPathMatcher("glob:**.jar");
+
+ private List parseShard(Path shardPath) throws IOException {
+ if (JAR_PATTERN.matches(shardPath)) {
+ List out = new ArrayList<>();
+ try (JarFile jar = new JarFile(shardPath.toFile())) {
+ Enumeration entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ if (entry.getName().endsWith(".scip")) {
+ try (InputStream is = jar.getInputStream(entry)) {
+ byte[] bytes = InputStreamBytes.readAll(is);
+ out.add(parseBytes(bytes));
+ }
+ }
+ }
+ }
+ return out;
+ }
+ return Collections.singletonList(parseBytes(Files.readAllBytes(shardPath)));
+ }
+
+ private static Scip.Index parseBytes(byte[] bytes) throws IOException {
+ CodedInputStream in = CodedInputStream.newInstance(bytes);
+ in.setRecursionLimit(1000);
+ return Scip.Index.parseFrom(in);
+ }
+
+ // --- rewriting -----------------------------------------------------------
+
+ private Scip.Document rewriteDocument(Scip.Document doc) {
+ Scip.Document.Builder builder = doc.toBuilder().clearOccurrences().clearSymbols();
+ for (Scip.Occurrence occ : doc.getOccurrencesList()) {
+ builder.addOccurrences(occ.toBuilder().setSymbol(rewriter.rewrite(occ.getSymbol())).build());
+ }
+ for (Scip.SymbolInformation info : doc.getSymbolsList()) {
+ builder.addSymbols(rewriteSymbol(info));
+ }
+ return builder.build();
+ }
+
+ private Scip.SymbolInformation rewriteSymbol(Scip.SymbolInformation info) {
+ Scip.SymbolInformation.Builder builder = info.toBuilder();
+ builder.setSymbol(rewriter.rewrite(info.getSymbol()));
+ if (!info.getEnclosingSymbol().isEmpty()) {
+ builder.setEnclosingSymbol(rewriter.rewrite(info.getEnclosingSymbol()));
+ }
+ builder.clearRelationships();
+ for (Scip.Relationship rel : info.getRelationshipsList()) {
+ builder.addRelationships(
+ rel.toBuilder().setSymbol(rewriter.rewrite(rel.getSymbol())).build());
+ }
+ return builder.build();
+ }
+
+ private void mergeInto(Scip.Document.Builder target, Scip.Document fresh) {
+ // Deduplicate occurrences by (range, symbol, roles) so that shards produced by repeated
+ // compilation rounds (or by multiple targetroots) don't introduce duplicate entries.
+ // Variants that differ only by enclosing_range are collapsed, preferring the one that has it.
+ LinkedHashMap occurrences = new LinkedHashMap<>();
+ for (Scip.Occurrence occ : target.getOccurrencesList()) putOccurrence(occurrences, occ);
+ for (Scip.Occurrence occ : fresh.getOccurrencesList()) putOccurrence(occurrences, occ);
+ target.clearOccurrences().addAllOccurrences(occurrences.values());
+
+ // Deduplicate symbols by symbol string; merge relationships of duplicates.
+ LinkedHashMap bySymbol = new LinkedHashMap<>();
+ for (Scip.SymbolInformation info : target.getSymbolsList()) {
+ bySymbol.put(info.getSymbol(), info);
+ }
+ for (Scip.SymbolInformation info : fresh.getSymbolsList()) {
+ Scip.SymbolInformation existing = bySymbol.get(info.getSymbol());
+ bySymbol.put(info.getSymbol(), existing == null ? info : mergeSymbol(existing, info));
+ }
+ target.clearSymbols().addAllSymbols(bySymbol.values());
+ }
+
+ private static void putOccurrence(
+ LinkedHashMap out, Scip.Occurrence occ) {
+ OccurrenceKey key = OccurrenceKey.of(occ);
+ Scip.Occurrence existing = out.get(key);
+ if (existing == null) {
+ out.put(key, occ);
+ return;
+ }
+ if (existing.getEnclosingRangeCount() == 0 && occ.getEnclosingRangeCount() > 0) {
+ out.put(key, occ);
+ }
+ }
+
+ private static final class OccurrenceKey {
+ final String symbol;
+ final java.util.List range;
+ final int roles;
+
+ OccurrenceKey(String symbol, java.util.List range, int roles) {
+ this.symbol = symbol;
+ this.range = range;
+ this.roles = roles;
+ }
+
+ static OccurrenceKey of(Scip.Occurrence occ) {
+ return new OccurrenceKey(occ.getSymbol(), occ.getRangeList(), occ.getSymbolRoles());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof OccurrenceKey)) return false;
+ OccurrenceKey other = (OccurrenceKey) o;
+ return roles == other.roles && symbol.equals(other.symbol) && range.equals(other.range);
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(symbol, range, roles);
+ }
+ }
+
+ private static Scip.SymbolInformation mergeSymbol(
+ Scip.SymbolInformation a, Scip.SymbolInformation b) {
+ Scip.SymbolInformation.Builder builder = b.toBuilder();
+ LinkedHashMap rels = new LinkedHashMap<>();
+ for (Scip.Relationship r : a.getRelationshipsList()) rels.put(r, r);
+ for (Scip.Relationship r : b.getRelationshipsList()) rels.put(r, r);
+ builder.clearRelationships().addAllRelationships(rels.values());
+ return builder.build();
+ }
+
+ // --- metadata ------------------------------------------------------------
+
+ private Scip.Index metadata() {
+ return Scip.Index.newBuilder()
+ .setMetadata(
+ Scip.Metadata.newBuilder()
+ .setVersion(Scip.ProtocolVersion.UnspecifiedProtocolVersion)
+ .setProjectRoot(options.sourceroot.toUri().toString())
+ .setTextDocumentEncoding(Scip.TextEncoding.UTF8)
+ .setToolInfo(
+ Scip.ToolInfo.newBuilder()
+ .setName(options.toolInfo.getName())
+ .setVersion(options.toolInfo.getVersion())
+ .addAllArguments(options.toolInfo.getArgumentsList())))
+ .build();
+ }
+
+ // --- inverse relationships ----------------------------------------------
+
+ /**
+ * Collects symbols that override or implement other symbols, indexed by the overridden symbol.
+ * When a final document is emitted, the per-symbol entries are augmented with {@code
+ * is_implementation && is_reference} relationships pointing back to overriders.
+ */
+ private final class InverseReferenceRelationships {
+
+ private final Map> map = new LinkedHashMap<>();
+ private final boolean enabled = options.emitInverseRelationships;
+
+ void observe(Scip.Document doc) {
+ if (!enabled) return;
+ for (Scip.SymbolInformation info : doc.getSymbolsList()) {
+ if (info.getSymbol().isEmpty() || SymbolRewriter.isLocal(info.getSymbol())) continue;
+ if (!supportsReferenceRelationship(info)) continue;
+ for (Scip.Relationship rel : info.getRelationshipsList()) {
+ if (!rel.getIsImplementation()) continue;
+ if (rel.getSymbol().isEmpty() || SymbolRewriter.isLocal(rel.getSymbol())) continue;
+ map.computeIfAbsent(rel.getSymbol(), k -> new ArrayList<>()).add(info.getSymbol());
+ }
+ }
+ }
+
+ Scip.Document applyTo(Scip.Document doc) {
+ if (!enabled || map.isEmpty()) return doc;
+ Scip.Document.Builder builder = doc.toBuilder().clearSymbols();
+ for (Scip.SymbolInformation info : doc.getSymbolsList()) {
+ List overriders = map.get(info.getSymbol());
+ if (overriders == null || overriders.isEmpty()) {
+ builder.addSymbols(info);
+ continue;
+ }
+ Scip.SymbolInformation.Builder s = info.toBuilder();
+ for (String overrider : overriders) {
+ s.addRelationships(
+ Scip.Relationship.newBuilder()
+ .setSymbol(overrider)
+ .setIsImplementation(true)
+ .setIsReference(true));
+ }
+ builder.addSymbols(s.build());
+ }
+ return builder.build();
+ }
+ }
+
+ private static boolean supportsReferenceRelationship(Scip.SymbolInformation info) {
+ switch (info.getKind()) {
+ case Interface:
+ case Type:
+ case Class:
+ case Object:
+ case PackageObject:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SemanticdbWalker.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipShardWalker.java
similarity index 56%
rename from scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SemanticdbWalker.java
rename to scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipShardWalker.java
index c0cd0a717..04dbfff39 100644
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SemanticdbWalker.java
+++ b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipShardWalker.java
@@ -11,21 +11,26 @@
import java.util.ArrayList;
import java.util.List;
-/** A file visitor that recursively collects all SemanticDB files in a given directory. */
-public class SemanticdbWalker extends SimpleFileVisitor {
+/**
+ * A file visitor that recursively collects per-source SCIP shard files ({@code *.scip}) emitted by
+ * the compiler plug-ins. Only files under a {@code META-INF/scip/} directory are returned so we
+ * don't accidentally re-ingest a previously-written aggregate {@code index.scip} that may live in
+ * the same target tree.
+ */
+public class ScipShardWalker extends SimpleFileVisitor {
private final ArrayList result;
private final ScipSemanticdbOptions options;
- private final PathMatcher semanticdbPattern =
- FileSystems.getDefault().getPathMatcher("glob:**.semanticdb");
+ private final PathMatcher scipPattern =
+ FileSystems.getDefault().getPathMatcher("glob:**/META-INF/scip/**.scip");
- public SemanticdbWalker(ScipSemanticdbOptions options) {
+ public ScipShardWalker(ScipSemanticdbOptions options) {
this.options = options;
result = new ArrayList<>();
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- if (semanticdbPattern.matches(file)) {
+ if (scipPattern.matches(file)) {
result.add(file);
}
return super.visitFile(file, attrs);
@@ -37,13 +42,14 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) {
return FileVisitResult.CONTINUE;
}
- public static List findSemanticdbFiles(ScipSemanticdbOptions options) throws IOException {
- SemanticdbWalker walker = new SemanticdbWalker(options);
+ /** Returns all {@code *.scip} shard files reachable from {@code options.targetroots}. */
+ public static List findScipShards(ScipSemanticdbOptions options) throws IOException {
+ ScipShardWalker walker = new ScipShardWalker(options);
PathMatcher jarPattern = FileSystems.getDefault().getPathMatcher("glob:**.jar");
for (Path root : options.targetroots) {
if (jarPattern.matches(root)) {
walker.result.add(root);
- } else {
+ } else if (Files.exists(root)) {
Files.walkFileTree(root, walker);
}
}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipTextDocument.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipTextDocument.java
deleted file mode 100644
index 4b6307a88..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipTextDocument.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb;
-
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Wrapper around a SemanticDB TextDocument with SCIP-related utilities. */
-public class ScipTextDocument {
- public final Path semanticdbPath;
- public final Semanticdb.TextDocument semanticdb;
-
- public ScipTextDocument(
- Path semanticdbPath, Semanticdb.TextDocument semanticdb, Path sourceroot) {
- this.semanticdbPath = semanticdbPath;
- String uri = sourceroot.resolve(semanticdb.getUri()).toUri().toString();
- this.semanticdb = Semanticdb.TextDocument.newBuilder(semanticdb).setUri(uri).build();
- }
-
- @Override
- public String toString() {
- return "ScipDocument{" + "path=" + semanticdbPath + ", semanticdb=" + semanticdb + '}';
- }
-
- public List sortedSymbolOccurrences() {
- return ScipTextDocument.sortedSymbolOccurrences(semanticdb);
- }
-
- public static List sortedSymbolOccurrences(
- Semanticdb.TextDocument semanticdb) {
- ArrayList result =
- new ArrayList<>(semanticdb.getOccurrencesList().size());
- result.addAll(semanticdb.getOccurrencesList());
- for (Semanticdb.Synthetic synthetic : semanticdb.getSyntheticsList()) {
- addAllSyntheticOccurrences(synthetic, result);
- }
- result.sort((o1, o2) -> new RangeComparator().compare(o1.getRange(), o2.getRange()));
- return result;
- }
-
- private static void addAllSyntheticOccurrences(
- Semanticdb.Synthetic synthetic, ArrayList buffer) {
- Semanticdb.Range offsetRange =
- Semanticdb.Range.newBuilder(synthetic.getRange())
- .setStartLine(synthetic.getRange().getEndLine())
- .setStartCharacter(synthetic.getRange().getEndCharacter())
- .build();
- new SemanticdbTreeVisitor() {
- @Override
- void visitIdTree(Semanticdb.IdTree tree) {
- Semanticdb.SymbolOccurrence syntheticOccurrence =
- Semanticdb.SymbolOccurrence.newBuilder()
- .setRange(offsetRange)
- .setSymbol(tree.getSymbol())
- .setRole(Semanticdb.SymbolOccurrence.Role.REFERENCE)
- .build();
- buffer.add(syntheticOccurrence);
- }
- }.visitTree(synthetic.getTree());
- }
-}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipWriter.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipWriter.java
index 2b323740b..3a16d7db5 100644
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipWriter.java
+++ b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipWriter.java
@@ -49,6 +49,10 @@ public void emitTyped(Scip.Index index) {
public void build() throws IOException {
close();
+ Path parent = options.output.getParent();
+ if (parent != null) {
+ Files.createDirectories(parent);
+ }
Files.move(tmp, options.output, StandardCopyOption.REPLACE_EXISTING);
}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SemanticdbTreeVisitor.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SemanticdbTreeVisitor.java
deleted file mode 100644
index 3ecd82a48..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SemanticdbTreeVisitor.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb.*;
-
-public abstract class SemanticdbTreeVisitor {
- public void visitTree(Tree tree) {
- if (tree.hasApplyTree()) {
- this.visitApplyTree(tree.getApplyTree());
- } else if (tree.hasFunctionTree()) {
- this.visitFunctionTree(tree.getFunctionTree());
- } else if (tree.hasIdTree()) {
- this.visitIdTree(tree.getIdTree());
- } else if (tree.hasLiteralTree()) {
- this.visitLiteralTree(tree.getLiteralTree());
- } else if (tree.hasMacroExpansionTree()) {
- this.visitMacroExpansionTree(tree.getMacroExpansionTree());
- } else if (tree.hasOriginalTree()) {
- this.visitOriginalTree(tree.getOriginalTree());
- } else if (tree.hasSelectTree()) {
- this.visitSelectTree(tree.getSelectTree());
- } else if (tree.hasTypeApplyTree()) {
- this.visitTypeApplyTree(tree.getTypeApplyTree());
- } else if (tree.hasAnnotationTree()) {
- this.visitAnnotationTree(tree.getAnnotationTree());
- } else if (tree.hasAssignTree()) {
- this.visitAssignTree(tree.getAssignTree());
- } else if (tree.hasBinopTree()) {
- this.visitBinaryOperatorTree(tree.getBinopTree());
- }
- }
-
- void visitApplyTree(ApplyTree tree) {
- visitTree(tree.getFunction());
- for (Tree argument : tree.getArgumentsList()) {
- visitTree(argument);
- }
- }
-
- void visitFunctionTree(FunctionTree tree) {
- for (IdTree parameter : tree.getParametersList()) {
- visitIdTree(parameter);
- }
- visitTree(tree.getBody());
- }
-
- void visitIdTree(IdTree tree) {}
-
- void visitLiteralTree(LiteralTree tree) {}
-
- void visitMacroExpansionTree(MacroExpansionTree tree) {
- visitTree(tree.getBeforeExpansion());
- }
-
- void visitOriginalTree(OriginalTree tree) {}
-
- void visitSelectTree(SelectTree tree) {
- visitTree(tree.getQualifier());
- visitIdTree(tree.getId());
- }
-
- void visitTypeApplyTree(TypeApplyTree tree) {
- visitTree(tree.getFunction());
- }
-
- void visitAnnotationTree(AnnotationTree tree) {
- for (Tree parameter : tree.getParametersList()) {
- visitTree(parameter);
- }
- }
-
- void visitAssignTree(AssignTree tree) {
- visitTree(tree.getLhs());
- visitTree(tree.getRhs());
- }
-
- void visitBinaryOperatorTree(BinaryOperatorTree tree) {
- visitTree(tree.getLhs());
- visitTree(tree.getRhs());
- }
-}
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
deleted file mode 100644
index fc306ad25..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatter.java
+++ /dev/null
@@ -1,822 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolInformation.Property;
-import com.sourcegraph.semanticdb_javac.Semanticdb.*;
-
-import com.sourcegraph.semanticdb_javac.SemanticdbSymbols;
-
-import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-
-import static com.sourcegraph.semanticdb_javac.SemanticdbBuilders.typeRef;
-
-public class SignatureFormatter {
- private static final Type OBJECT_TYPE_REF = typeRef("java/lang/Object#");
- private static final Type PRODUCT_TYPE_REF = typeRef("scala/Product#");
- private static final Type SCALA_SERIALIZABLE_TYPE_REF = typeRef("scala/package.Serializable#");
- private static final Type JAVA_SERIALIZABLE_TYPE_REF = typeRef("java/util/Serializable#");
- private static final Type SCALA_ANY_TYPE_REF = typeRef("scala/Any#");
- private static final Type SCALA_ANYREF_TYPE_REF = typeRef("scala/AnyRef#");
-
- private static final Type WILDCARD_TYPE_REF = typeRef("local_wildcard");
-
- private static final Type NOTHING_SYMBOL = typeRef("scala/Nothing#");
- private static final String FUNCTION_SYMBOL_PREFIX = "scala/Function";
- // Special case scala/Function object to not conflict with Function1 for example
- private static final String FUNCTION_OBJECT = "scala/Function.";
- private static final String TUPLE_SYMBOL_PREFIX = "scala/Tuple";
- private static final String ARRAY_SYMBOL = "scala/Array#";
- private static final String ENUM_SYMBOL = "java/lang/Enum#";
- private static final String ANNOTATION_SYMBOL = "java/lang/annotation/Annotation#";
- private static final Set REDUNDANT_CLASS_PARENTS = new HashSet<>();
- private static final Set CASE_CLASS_PARENTS = new HashSet<>();
-
- {
- REDUNDANT_CLASS_PARENTS.add(OBJECT_TYPE_REF);
- REDUNDANT_CLASS_PARENTS.add(SCALA_ANY_TYPE_REF);
- REDUNDANT_CLASS_PARENTS.add(SCALA_ANYREF_TYPE_REF);
-
- CASE_CLASS_PARENTS.add(PRODUCT_TYPE_REF);
- CASE_CLASS_PARENTS.add(SCALA_SERIALIZABLE_TYPE_REF);
- CASE_CLASS_PARENTS.add(JAVA_SERIALIZABLE_TYPE_REF);
- }
-
- private final StringBuilder s = new StringBuilder();
- private final SymbolInformation symbolInformation;
- private final Symtab symtab;
- private final boolean isScala;
-
- public SignatureFormatter(SymbolInformation symbolInformation, Symtab symtab) {
- this.symbolInformation = symbolInformation;
- this.symtab = symtab;
- this.isScala = symbolInformation.getLanguage() == Language.SCALA;
- }
-
- public String formatSymbol() {
- try {
- return formatSymbolUnsafe();
- } catch (Exception e) {
- throw new SignatureFormatterException(symbolInformation, e);
- }
- }
-
- private String formatSymbolUnsafe() {
- Signature signature = symbolInformation.getSignature();
- if (signature.hasClassSignature()) {
- formatClassSignature(signature.getClassSignature());
- } else if (signature.hasMethodSignature()) {
- formatMethodSignature(signature.getMethodSignature());
- } else if (signature.hasValueSignature()) {
- formatValueSignature(signature.getValueSignature());
- } else if (signature.hasTypeSignature()) {
- formatTypeParameterSignature(signature.getTypeSignature());
- }
- return s.toString();
- }
-
- private void formatClassSignature(ClassSignature classSignature) {
- boolean isAnnotation =
- classSignature.getParentsList().stream()
- .anyMatch(t -> t.getTypeRef().getSymbol().equals(ANNOTATION_SYMBOL));
-
- boolean isEnum = has(Property.ENUM);
- boolean isInterface = symbolInformation.getKind() == SymbolInformation.Kind.INTERFACE;
-
- printKeywordln(formatAnnotations());
-
- printKeyword(formatAccess());
- if (!isEnum && !isAnnotation && !isInterface) printKeyword(formatModifiers());
-
- switch (symbolInformation.getKind()) {
- case CLASS:
- if (isEnum) {
- printKeyword("enum");
- } else {
- printKeyword("class");
- }
- break;
- case INTERFACE:
- if (isAnnotation) {
- printKeyword("@interface");
- break;
- }
- printKeyword("interface");
- break;
- case OBJECT:
- printKeyword("object");
- break;
- case TRAIT:
- printKeyword("trait");
- break;
- case PACKAGE_OBJECT:
- printKeyword("package object");
- break;
- default:
- break;
- }
- s.append(symbolInformation.getDisplayName());
- if (symbolInformation.getKind() == SymbolInformation.Kind.CLASS && has(Property.CASE)) {
- primaryConstructor(classSignature)
- .ifPresent(
- constructorSignature ->
- formatScalaParameterList(constructorSignature.getParameterListsList()));
- }
-
- List typeParameters = getSymlinks(classSignature.getTypeParameters());
- if (!typeParameters.isEmpty()) {
- s.append(
- typeParameters.stream()
- .map(this::formatTypeParameter)
- .collect(Collectors.joining(", ", isScala ? "[" : "<", isScala ? "]" : ">")));
- }
-
- boolean hasNonRedundantParent =
- classSignature.getParentsList().size() > 0
- && !REDUNDANT_CLASS_PARENTS.contains(classSignature.getParentsList().get(0));
-
- boolean isCaseClass =
- isScala
- && symbolInformation.getKind() == SymbolInformation.Kind.CLASS
- && has(Property.CASE);
-
- List nonSyntheticParents =
- classSignature.getParentsList().stream()
- .filter(parent -> !REDUNDANT_CLASS_PARENTS.contains(parent))
- .filter(parent -> !parent.getTypeRef().getSymbol().equals(ENUM_SYMBOL))
- .filter(parent -> isCaseClass && !CASE_CLASS_PARENTS.contains(parent))
- .filter(parent -> !parent.getTypeRef().getSymbol().equals(ANNOTATION_SYMBOL))
- .collect(Collectors.toList());
-
- if (nonSyntheticParents.isEmpty()) return;
-
- if (isScala) {
- printKeyword(" extends");
- s.append(
- nonSyntheticParents.stream().map(this::formatType).collect(Collectors.joining(" with ")));
- return;
- }
-
- // Determine which parents from ClassSignature.parents are classes or interfaces so we know to
- // use
- // 'extends' or 'implements'.
- // The logic is as follows:
- // 1. If the symbol has type CLASS, there will always be at least 1 parent. For enums, this is
- // java/lang/Enum#, otherwise it is java/lang/Object# if no superclass is specified.
- // Therefore, if the parents list contains java/lang/Object# type or the symbol is an enum,
- // then no superclass was defined and all parents are interfaces and we must print
- // 'implements'
- // followed by all superinterfaces.
- // Else if it is not an enum and the list of non-synthetic parents is non empty, a superclass
- // was specified and we must print it with the 'extends' keyword prefixed, followed by
- // 'implements' and all superinterfaces, if any.
- // 2. If the symbol has type INTERFACE, then any defined parents must also be interfaces, so if
- // the list of non-synthetic parents is not empty, print 'implements' and all
- // superinterfaces.
- switch (symbolInformation.getKind()) {
- case CLASS:
- // if no superclass or is an enum, every non synthetic parent is an interface
- if (isEnum || !hasNonRedundantParent) {
- printKeyword(" implements");
-
- String superInterfaces =
- nonSyntheticParents.stream().map(this::formatType).collect(Collectors.joining(", "));
- s.append(superInterfaces);
- } else {
- // else if has a superclass and is not an enum
- printKeyword(" extends");
- s.append(formatType(nonSyntheticParents.get(0)));
-
- String superInterfaces =
- nonSyntheticParents.stream()
- .skip(1)
- .map(this::formatType)
- .collect(Collectors.joining(", "));
- if (!superInterfaces.isEmpty()) {
- printKeyword(" implements");
- s.append(superInterfaces);
- }
- }
- break;
- case INTERFACE:
- // can only extend other interfaces
- printKeyword(" extends");
-
- String superInterfaces =
- nonSyntheticParents.stream().map(this::formatType).collect(Collectors.joining(", "));
- s.append(superInterfaces);
- }
- }
-
- private void formatMethodSignature(MethodSignature methodSignature) {
- if (isScala) {
- formatScalaMethodSignature(methodSignature);
- return;
- }
-
- printKeywordln(formatAnnotations());
- printKeyword(formatAccess());
- printKeyword(formatModifiers());
-
- List typeParameters = getSymlinks(methodSignature.getTypeParameters());
- if (!typeParameters.isEmpty()) {
- printKeyword(
- typeParameters.stream()
- .map(this::formatTypeParameter)
- .collect(Collectors.joining(", ", "<", ">")));
- }
-
- if (symbolInformation.getKind() == SymbolInformation.Kind.CONSTRUCTOR) {
- String owner = SymbolDescriptor.parseFromSymbol(symbolInformation.getSymbol()).owner;
- // Fix for https://github.com/sourcegraph/scip-java/issues/150
- if (!owner.equals(SemanticdbSymbols.NONE)) {
- s.append(SymbolDescriptor.parseFromSymbol(owner).descriptor.name);
- }
- } else {
- printKeyword(formatType(methodSignature.getReturnType()));
- s.append(symbolInformation.getDisplayName());
- }
-
- s.append(
- methodSignature.getParameterListsList().stream()
- .flatMap((params) -> getSymlinks(params).stream())
- .map(this::formatTermParameter)
- .collect(Collectors.joining(", ", "(", ")")));
-
- if (!methodSignature.getThrowsList().isEmpty()) {
- printKeyword(" throws");
- s.append(
- methodSignature.getThrowsList().stream()
- .map(this::formatType)
- .collect(Collectors.joining(", ")));
- }
- }
-
- private String formatTermParameter(SymbolInformation info) {
- if (info == null) return "";
- if (isScala) {
- return info.getDisplayName()
- + ": "
- + formatType(info.getSignature().getValueSignature().getTpe());
- }
- return formatType(info.getSignature().getValueSignature().getTpe())
- + " "
- + info.getDisplayName();
- }
-
- private void formatScalaMethodSignature(MethodSignature methodSignature) {
- printKeywordln(formatAnnotations());
- printKeyword(formatAccess());
- printKeyword(formatModifiers());
- if (has(Property.VAL)) {
- printKeyword("val");
- } else if (has(Property.VAR)) {
- printKeyword("var");
- } else {
- printKeyword("def");
- }
- s.append(
- symbolInformation.getKind() == SymbolInformation.Kind.CONSTRUCTOR
- ? "this"
- : symbolInformation.getDisplayName());
- formatScalaParameterList(methodSignature.getParameterListsList());
- if (symbolInformation.getKind() != SymbolInformation.Kind.CONSTRUCTOR) {
- printKeyword(":");
- s.append(this.formatType(methodSignature.getReturnType()));
- }
- }
-
- private Optional primaryConstructor(ClassSignature classSignature) {
- Symtab scopeSymtab = symtab.withHardlinks(classSignature.getDeclarations());
- int n = classSignature.getDeclarations().getSymlinksCount();
- for (int i = 0; i < n; i++) {
- String symlink = classSignature.getDeclarations().getSymlinks(i);
- SymbolInformation info = scopeSymtab.symbols.get(symlink);
- if (info != null
- && info.getKind() == SymbolInformation.Kind.CONSTRUCTOR
- && has(Property.PRIMARY, info)
- && info.hasSignature()
- && info.getSignature().hasMethodSignature()) {
- return Optional.of(info.getSignature().getMethodSignature());
- }
- }
- return Optional.empty();
- }
-
- private void formatScalaParameterList(List parameterList) {
- for (Scope scope : parameterList) {
- List infos =
- scope.getHardlinksCount() > 0 ? scope.getHardlinksList() : getSymlinks(scope);
- s.append(
- infos.stream()
- .map(this::formatTermParameter)
- .collect(Collectors.joining(", ", "(", ")")));
- }
- }
-
- private void formatValueSignature(ValueSignature valueSignature) {
- printKeywordln(formatAnnotations());
- if (isEnumConstant()) {
- String ownerSym = SymbolDescriptor.parseFromSymbol(symbolInformation.getSymbol()).owner;
- SymbolInformation ownerInfo = symtab.symbols.get(ownerSym);
- List enumConstants =
- getSymlinks(ownerInfo.getSignature().getClassSignature().getDeclarations()).stream()
- .filter(Objects::nonNull)
- .filter(this::isEnumConstant)
- .collect(Collectors.toList());
- int ordinal = enumConstants.indexOf(symbolInformation);
- s.append(ownerInfo.getDisplayName()).append('.');
- s.append(this.symbolInformation.getDisplayName());
- s.append(" /* ordinal ").append(ordinal).append(" */");
- } else {
- printKeyword(formatAccess());
- printKeyword(formatModifiers());
- if (isScala) {
- s.append(symbolInformation.getDisplayName());
- printKeyword(":");
- printKeyword(formatType(valueSignature.getTpe()));
- } else {
- printKeyword(formatType(valueSignature.getTpe()));
- s.append(symbolInformation.getDisplayName());
- }
- }
- }
-
- private void formatTypeParameterSignature(TypeSignature typeSignature) {
- if (isScala && symbolInformation.getKind() == SymbolInformation.Kind.TYPE) {
- printKeyword("type");
- }
- s.append(symbolInformation.getDisplayName());
- if (typeSignature.hasLowerBound()
- && (!isScala || !typeSignature.getLowerBound().equals(NOTHING_SYMBOL))) {
- printKeyword(isScala ? " >:" : " super");
- s.append(formatType(typeSignature.getLowerBound()));
- }
- if (typeSignature.hasUpperBound()
- && !typeSignature.getUpperBound().equals(isScala ? SCALA_ANY_TYPE_REF : OBJECT_TYPE_REF)) {
- printKeyword(isScala ? " <:" : " extends");
- s.append(formatType(typeSignature.getUpperBound()));
- }
- }
-
- /**
- * Transforms symlinks from a Scope into a List of SymbolInformation's looked up in the Symtab.
- */
- private List getSymlinks(Scope scope) {
- ArrayList symlinks = new ArrayList<>();
- for (int i = 0; i < scope.getSymlinksCount(); i++) {
- SymbolInformation info = symtab.symbols.get(scope.getSymlinks(i));
- if (info != null) {
- symlinks.add(info);
- }
- }
- return symlinks;
- }
-
- /**
- * Formats one of a method's/class's type parameter symbols through recursion from the
- * SymbolInformation extracted from the Symtab. This works by the signature being a TypeSignature.
- */
- private String formatTypeParameter(SymbolInformation typeInfo) {
- return new SignatureFormatter(typeInfo, symtab).formatSymbol();
- }
-
- private String formatTypeArguments(List typeArguments) {
- if (typeArguments.isEmpty()) return "";
-
- return typeArguments.stream()
- .map(this::formatType)
- .collect(Collectors.joining(", ", isScala ? "[" : "<", isScala ? "]" : ">"));
- }
-
- private String formatAnnotations() {
- return formatAnnotations(symbolInformation);
- }
-
- private String formatAnnotations(SymbolInformation symInfo) {
- return symInfo.getAnnotationsList().stream()
- .map(this::formatAnnotation)
- .collect(Collectors.joining("\n"));
- }
-
- private String formatAnnotation(AnnotationTree annotation) {
- StringBuilder b = new StringBuilder();
- b.append('@');
- b.append(formatType(annotation.getTpe()));
-
- if (annotation.getParametersCount() == 1) {
- b.append('(');
-
- Tree parameter = annotation.getParameters(0);
- // if only 1 parameter, and its LHS is named 'value', we can omit the 'value = '
- // https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.7.3
- AssignTree firstParam = parameter.getAssignTree();
- if (parameter.hasAssignTree()
- && SymbolDescriptor.parseFromSymbol(firstParam.getLhs().getIdTree().getSymbol())
- .descriptor
- .name
- .equals("value")) {
- b.append(formatTree(firstParam.getRhs()));
- } else {
- b.append(formatTree(parameter));
- }
-
- b.append(')');
- } else if (annotation.getParametersCount() > 1) {
- b.append('(');
- String parameter =
- annotation.getParametersList().stream()
- .map(this::formatTree)
- .collect(Collectors.joining(", "));
- b.append(parameter);
- b.append(')');
- }
-
- return b.toString();
- }
-
- private String formatTree(Tree tree) {
- if (tree.hasIdTree()) {
- return SymbolDescriptor.parseFromSymbol(tree.getIdTree().getSymbol()).descriptor.name;
- } else if (tree.hasLiteralTree()) {
- return formatConstant(tree.getLiteralTree().getConstant());
- } else if (tree.hasSelectTree()) {
- return formatTree(tree.getSelectTree().getQualifier())
- + "."
- + SymbolDescriptor.parseFromSymbol(tree.getSelectTree().getId().getSymbol())
- .descriptor
- .name;
- } else if (tree.hasAnnotationTree()) {
- return formatAnnotation(tree.getAnnotationTree());
- } else if (tree.hasApplyTree()) {
- if (tree.getApplyTree().getFunction().hasIdTree()
- && tree.getApplyTree().getFunction().getIdTree().getSymbol().equals(ARRAY_SYMBOL)) {
- return tree.getApplyTree().getArgumentsList().stream()
- .map(this::formatTree)
- .collect(Collectors.joining(", ", "{", "}"));
- } else {
- 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());
- } else if (tree.hasAssignTree()) {
- return formatTree(tree.getAssignTree().getLhs())
- + " = "
- + 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);
- }
-
- 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()";
- } else if (constant.hasBooleanConstant()) {
- return Boolean.toString(constant.getBooleanConstant().getValue());
- } else if (constant.hasByteConstant()) {
- return Integer.toString(constant.getByteConstant().getValue());
- } else if (constant.hasShortConstant()) {
- return Integer.toString(constant.getShortConstant().getValue());
- } else if (constant.hasCharConstant()) {
- return String.format("'%s'", (char) constant.getCharConstant().getValue());
- } else if (constant.hasIntConstant()) {
- return Integer.toString(constant.getIntConstant().getValue());
- } else if (constant.hasLongConstant()) {
- return Long.toString(constant.getLongConstant().getValue());
- } else if (constant.hasFloatConstant()) {
- return Float.toString(constant.getFloatConstant().getValue()) + 'f';
- } else if (constant.hasDoubleConstant()) {
- return Double.toString(constant.getDoubleConstant().getValue());
- } else if (constant.hasStringConstant()) {
- return '"' + constant.getStringConstant().getValue() + '"';
- } else if (constant.hasNullConstant()) {
- return "null";
- }
- 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()) {
- TypeRef typeRef = type.getTypeRef();
- if (typeRef.getSymbol().equals(ARRAY_SYMBOL)) {
- if (isScala) {
- b.append("Array[");
- b.append(formatType(typeRef.getTypeArguments(0)));
- b.append("]");
- } else {
- b.append(formatType(typeRef.getTypeArguments(0)));
- b.append("[]");
- }
- } else if (isScala
- && typeRef.getSymbol().startsWith(FUNCTION_SYMBOL_PREFIX)
- && typeRef.getTypeArgumentsCount() > 0
- && !typeRef.getSymbol().startsWith(FUNCTION_OBJECT)) {
- int n = typeRef.getTypeArgumentsCount() - 1;
- if (n == 0) {
- // Special-case for Function1[A, B]: don't wrap `A` in parenthesis like this `(A) => B`
- s.append(formatType(typeRef.getTypeArguments(0)));
- } else {
- b.append(
- typeRef.getTypeArgumentsList().stream()
- .limit(Math.max(0, n))
- .map(this::formatType)
- .collect(Collectors.joining(", ", "(", ")")));
- }
- b.append(" => ");
- b.append(formatType(typeRef.getTypeArguments(n)));
- } else if (isScala && typeRef.getSymbol().startsWith(TUPLE_SYMBOL_PREFIX)) {
- b.append(
- typeRef.getTypeArgumentsList().stream()
- .map(this::formatType)
- .collect(Collectors.joining(", ", "(", ")")));
- } else {
- b.append(symbolDisplayName(typeRef.getSymbol()));
- b.append(formatTypeArguments(typeRef.getTypeArgumentsList()));
- }
- } else if (type.hasSingleType()) {
- SingleType tpe = type.getSingleType();
- if (tpe.hasPrefix()) {
- b.append(formatType(tpe.getPrefix()));
- }
- SymbolInformation info = symtab.symbols.get(tpe.getSymbol());
- if (info != null) {
- b.append(info.getDisplayName()).append(".type");
- }
- } else if (type.hasThisType()) {
- b.append("this.type");
- } else if (type.hasSuperType()) {
- SuperType tpe = type.getSuperType();
- if (tpe.hasPrefix()) {
- b.append(formatType(tpe.getPrefix())).append(".");
- }
- b.append("super");
- } else if (type.hasConstantType()) {
- b.append(this.formatConstant(type.getConstantType().getConstant()));
- } else if (type.hasIntersectionType()) {
- b.append(
- type.getIntersectionType().getTypesList().stream()
- .map(this::formatType)
- .collect(Collectors.joining(isScala ? " with " : " & ")));
- } else if (type.hasUnionType()) {
- b.append(
- type.getIntersectionType().getTypesList().stream()
- .map(this::formatType)
- .collect(Collectors.joining(" | ")));
- } else if (type.hasStructuralType()) {
- StructuralType tpe = type.getStructuralType();
- int n = tpe.getDeclarations().getHardlinksCount();
- if (n == 0) {
- b.append(" {}");
- } else {
- b.append(formatType(tpe.getTpe())).append(" {");
- Symtab hardlinkSymtab = symtab.withHardlinks(tpe.getDeclarations());
- for (int i = 0; i < n; i++) {
- SymbolInformation info = tpe.getDeclarations().getHardlinks(i);
- if (i > 0) {
- b.append(";");
- }
- b.append(" ").append(new SignatureFormatter(info, hardlinkSymtab).formatSymbol());
- }
- b.append(" }");
- }
- } else if (type.hasExistentialType()) {
- AtomicInteger hardlinkStep = new AtomicInteger();
- TypeRef typeRef = type.getExistentialType().getTpe().getTypeRef();
- b.append(symbolDisplayName(type.getExistentialType().getTpe().getTypeRef().getSymbol()));
- b.append(
- typeRef.getTypeArgumentsList().stream()
- .map(
- (typeArg) -> {
- // if hardlink (aka wildcard) we need to reach into declarations at index
- // hardlinkStep
- if (typeArg.equals(WILDCARD_TYPE_REF)) {
- SymbolInformation hardlink =
- type.getExistentialType()
- .getDeclarations()
- .getHardlinks(hardlinkStep.getAndIncrement());
- return symbolDisplayName(hardlink.getSymbol())
- + new SignatureFormatter(hardlink, symtab).formatSymbol();
- }
- // else for symlink we can use the usual path
- return formatType(typeArg);
- })
- .collect(Collectors.joining(", ", isScala ? "[" : "<", isScala ? "[" : ">")));
- } else if (type.hasByNameType()) {
- b.append("=> ").append(formatType(type.getByNameType().getTpe()));
- } else if (type.hasRepeatedType()) {
- b.append(formatType(type.getRepeatedType().getTpe())).append("*");
- }
-
- return b.toString().trim();
- }
-
- private String formatAccess() {
- Access access = symbolInformation.getAccess();
- if (access.hasPrivateAccess()) {
- return "private";
- } else if (!isScala && access.hasPublicAccess()) {
- return "public";
- } else if (access.hasProtectedAccess()) {
- return "protected";
- } else if (isScala && access.hasPrivateThisAccess()) {
- return "private[this]";
- } else if (isScala && access.hasPrivateWithinAccess()) {
- String name =
- SymbolDescriptor.parseFromSymbol(access.getPrivateWithinAccess().getSymbol())
- .descriptor
- .name;
- return String.format("protected[%s]", name);
- }
- return "";
- }
-
- // https://checkstyle.sourceforge.io/config_modifier.html#ModifierOrder
- private String formatModifiers() {
- ArrayList modifiers = new ArrayList<>();
- if (has(Property.ABSTRACT)) {
- if (isScala && symbolInformation.getKind() != SymbolInformation.Kind.CLASS) {
- } else {
- modifiers.add("abstract");
- }
- }
- if (has(Property.DEFAULT)) modifiers.add("default");
- if (has(Property.STATIC)) modifiers.add("static");
- if (has(Property.FINAL)) {
- if (symbolInformation.getKind() != SymbolInformation.Kind.OBJECT
- && symbolInformation.getKind() != SymbolInformation.Kind.PACKAGE_OBJECT) {
- modifiers.add("final");
- }
- }
- if (has(Property.IMPLICIT)) modifiers.add("implicit");
- if (has(Property.SEALED)) modifiers.add("sealed");
- if (has(Property.CASE)) modifiers.add("case");
- return String.join(" ", modifiers);
- }
-
- private void printKeyword(String keyword) {
- if (keyword.isEmpty()) return;
- s.append(keyword).append(' ');
- }
-
- private void printKeywordln(String keyword) {
- if (keyword.isEmpty()) return;
- s.append(keyword).append('\n');
- }
-
- private boolean isEnumConstant(SymbolInformation symInfo) {
- if (!(has(Property.ENUM, symInfo)
- && has(Property.FINAL, symInfo)
- && has(Property.STATIC, symInfo)
- && symInfo.getAccess().hasPublicAccess())) {
- return false;
- }
- SymbolInformation owner =
- symtab.symbols.get(SymbolDescriptor.parseFromSymbol(symInfo.getSymbol()).owner);
- if (owner == null) return false;
- return owner.getKind() == SymbolInformation.Kind.CLASS && has(Property.ENUM, owner);
- }
-
- private boolean isEnumConstant() {
- return isEnumConstant(symbolInformation);
- }
-
- private boolean has(Property property, SymbolInformation symInfo) {
- return (symInfo.getProperties() & property.getNumber()) > 0;
- }
-
- private boolean has(Property property) {
- return has(property, symbolInformation);
- }
-
- /**
- * Transforms a SemanticDB symbol string into its Java identifier display string. As SemanticDB
- * uses Scala "primitive" types for Java primitives (but not for Java boxing primitive wrappers),
- * we check for those first before attempting to decode a SemanticDB symbol.
- */
- public String symbolDisplayName(String symbol) {
- if (isScala) {
- return symbolScalaDisplayName(symbol);
- }
- return symbolJavaDisplayName(symbol);
- }
-
- private String symbolScalaDisplayName(String symbol) {
- if ("local_wildcard".equals(symbol)) {
- return "*";
- }
- return SymbolDescriptor.parseFromSymbol(symbol).descriptor.name;
- }
-
- private String symbolJavaDisplayName(String symbol) {
- switch (symbol) {
- case "local_wildcard":
- return "?";
- case "scala/Boolean#":
- return "boolean";
- case "scala/Byte#":
- return "byte";
- case "scala/Short#":
- return "short";
- case "scala/Int#":
- return "int";
- case "scala/Long#":
- return "long";
- case "scala/Char#":
- return "char";
- case "scala/Float#":
- return "float";
- case "scala/Double#":
- return "double";
- case "scala/Unit#":
- return "void";
- default:
- return SymbolDescriptor.parseFromSymbol(symbol).descriptor.name;
- }
- }
-}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatterException.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatterException.java
deleted file mode 100644
index 5c094aebc..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SignatureFormatterException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb;
-
-public class SignatureFormatterException extends RuntimeException {
- public SignatureFormatterException(
- Semanticdb.SymbolInformation symbolInformation, Throwable cause) {
- super(
- String.format(
- "failed to format symbol '%s'\n%s", symbolInformation.getSymbol(), symbolInformation),
- cause);
- }
-
- @Override
- public synchronized Throwable fillInStackTrace() {
- // This exception doesn't have a relevant stack trace. The cause exception
- // already points to the culprit filename and line number.
- return this;
- }
-}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SymbolOccurrences.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SymbolOccurrences.java
deleted file mode 100644
index b4d309491..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SymbolOccurrences.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SymbolOccurrences {
- public List occurrences = new ArrayList<>();
-
- public void addSyntheticDefinition(String sym) {
- occurrences.add(
- Semanticdb.SymbolOccurrence.newBuilder()
- .setSymbol(sym)
- .setRole(Semanticdb.SymbolOccurrence.Role.SYNTHETIC_DEFINITION)
- .build());
- }
-
- public void addDefinition(String sym) {
- occurrences.add(
- Semanticdb.SymbolOccurrence.newBuilder()
- .setSymbol(sym)
- .setRole(Semanticdb.SymbolOccurrence.Role.DEFINITION)
- .build());
- }
-}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SymbolRewriter.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SymbolRewriter.java
new file mode 100644
index 000000000..227ffdcd1
--- /dev/null
+++ b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/SymbolRewriter.java
@@ -0,0 +1,58 @@
+package com.sourcegraph.scip_semanticdb;
+
+/**
+ * Rewrites placeholder SCIP global symbols emitted by the compiler plugin into their final form.
+ *
+ * The compiler plugin does not know the Maven coordinates ({@code groupId:artifactId:version})
+ * of the source it is compiling, so it emits global symbols with the sentinel prefix {@code ". . .
+ * . "}. The aggregator resolves the appropriate coordinates via {@link PackageTable} and rewrites
+ * those symbols to the final {@code "scip-java"} scheme.
+ *
+ *
{@code local N} symbols are passed through unchanged.
+ */
+public final class SymbolRewriter {
+
+ /**
+ * Sentinel prefix used by the compiler plugin for global symbols whose coordinates are not yet
+ * known.
+ */
+ public static final String PLACEHOLDER_PREFIX = ". . . . ";
+
+ /** SCIP scheme used for symbols produced by scip-java. */
+ public static final String SCIP_JAVA_SCHEME = "scip-java";
+
+ private final PackageTable packages;
+
+ public SymbolRewriter(PackageTable packages) {
+ this.packages = packages;
+ }
+
+ /**
+ * Returns {@code true} if {@code symbol} is a placeholder global emitted by the compiler plugin.
+ */
+ public static boolean isPlaceholderGlobal(String symbol) {
+ return symbol != null && symbol.startsWith(PLACEHOLDER_PREFIX);
+ }
+
+ /**
+ * Returns {@code true} if {@code symbol} is a SCIP local symbol of the form {@code "local N"}.
+ */
+ public static boolean isLocal(String symbol) {
+ return symbol != null && symbol.startsWith("local ");
+ }
+
+ /**
+ * Rewrites a placeholder global symbol into its final form using the appropriate package
+ * coordinates from {@link PackageTable}. Local symbols and already-rewritten symbols are returned
+ * unchanged.
+ */
+ public String rewrite(String symbol) {
+ if (symbol == null || symbol.isEmpty()) return symbol;
+ if (isLocal(symbol)) return symbol;
+ if (!isPlaceholderGlobal(symbol)) return symbol;
+
+ String descriptor = symbol.substring(PLACEHOLDER_PREFIX.length());
+ Package pkg = packages.packageForSymbol(descriptor).orElse(Package.EMPTY);
+ return SCIP_JAVA_SCHEME + " " + pkg.scipTypedEncoding() + " " + descriptor;
+ }
+}
diff --git a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/Symtab.java b/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/Symtab.java
deleted file mode 100644
index 5324df0e5..000000000
--- a/scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/Symtab.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.sourcegraph.scip_semanticdb;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb;
-
-import java.util.HashMap;
-
-public class Symtab {
- public final HashMap symbols = new HashMap<>();
-
- public Symtab(Semanticdb.TextDocument document) {
- for (Semanticdb.SymbolInformation symbolInformation : document.getSymbolsList()) {
- symbols.put(symbolInformation.getSymbol(), symbolInformation);
- }
- }
-
- public Symtab withHardlinks(Semanticdb.Scope scope) {
- Symtab hardlinkSymtab = new Symtab(Semanticdb.TextDocument.getDefaultInstance());
- hardlinkSymtab.symbols.putAll(this.symbols);
- for (int i = 0; i < scope.getHardlinksCount(); i++) {
- Semanticdb.SymbolInformation info = scope.getHardlinks(i);
- hardlinkSymtab.symbols.put(info.getSymbol(), info);
- }
- return hardlinkSymtab;
- }
-}
diff --git a/semanticdb-java/BUILD b/semanticdb-java/BUILD
index 96f8844fb..d6955e206 100644
--- a/semanticdb-java/BUILD
+++ b/semanticdb-java/BUILD
@@ -1,24 +1,10 @@
-load("@rules_java//java:defs.bzl", "java_library", "java_proto_library")
-load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@rules_java//java:defs.bzl", "java_library")
package(
default_visibility = ["//visibility:public"],
)
-java_proto_library(
- name = "semanticdb_java_proto",
- deps = [":semanticdb_proto"],
-)
-
-proto_library(
- name = "semanticdb_proto",
- srcs = glob(["src/main/protobuf/*.proto"]),
-)
-
java_library(
name = "semanticdb-java",
srcs = glob(["src/main/java/**/*.java"]),
- deps = [
- "//semanticdb-java/src/main/protobuf:semanticdb_java_proto",
- ],
)
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
deleted file mode 100644
index f91e7a9ed..000000000
--- a/semanticdb-java/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbBuilders.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package com.sourcegraph.semanticdb_javac;
-
-import java.util.List;
-
-public class SemanticdbBuilders {
- // SemanticDB Types
- public static Semanticdb.Type typeRef(String symbol) {
- return Semanticdb.Type.newBuilder()
- .setTypeRef(Semanticdb.TypeRef.newBuilder().setSymbol(symbol))
- .build();
- }
-
- public static Semanticdb.Type typeRef(String symbol, List typeArguments) {
- return Semanticdb.Type.newBuilder()
- .setTypeRef(
- Semanticdb.TypeRef.newBuilder().setSymbol(symbol).addAllTypeArguments(typeArguments))
- .build();
- }
-
- public static Semanticdb.Type existentialType(
- Semanticdb.Type type, Semanticdb.Scope declarations) {
- return Semanticdb.Type.newBuilder()
- .setExistentialType(
- Semanticdb.ExistentialType.newBuilder().setTpe(type).setDeclarations(declarations))
- .build();
- }
-
- public static Semanticdb.Type intersectionType(List extends Semanticdb.Type> types) {
- return Semanticdb.Type.newBuilder()
- .setIntersectionType(Semanticdb.IntersectionType.newBuilder().addAllTypes(types))
- .build();
- }
-
- // SemanticDB Signatures
-
- public static Semanticdb.Signature signature(Semanticdb.ClassSignature.Builder signature) {
- return Semanticdb.Signature.newBuilder().setClassSignature(signature).build();
- }
-
- public static Semanticdb.Signature signature(Semanticdb.MethodSignature.Builder signature) {
- return Semanticdb.Signature.newBuilder().setMethodSignature(signature).build();
- }
-
- public static Semanticdb.Signature signature(Semanticdb.ValueSignature.Builder signature) {
- return Semanticdb.Signature.newBuilder().setValueSignature(signature).build();
- }
-
- public static Semanticdb.Signature signature(Semanticdb.TypeSignature.Builder signature) {
- return Semanticdb.Signature.newBuilder().setTypeSignature(signature).build();
- }
-
- // SemanticDB Symbols
-
- public static Semanticdb.SymbolOccurrence symbolOccurrence(
- String symbol,
- Semanticdb.Range range,
- Semanticdb.SymbolOccurrence.Role role,
- java.util.Optional enclosingRange) {
- Semanticdb.SymbolOccurrence.Builder builder =
- Semanticdb.SymbolOccurrence.newBuilder().setSymbol(symbol).setRange(range).setRole(role);
- enclosingRange.ifPresent(builder::setEnclosingRange);
- return builder.build();
- }
-
- public static Semanticdb.SymbolInformation.Builder symbolInformation(String symbol) {
- return Semanticdb.SymbolInformation.newBuilder().setSymbol(symbol);
- }
-
- // SemanticDB Access
-
- public static Semanticdb.Access privateAccess() {
- return Semanticdb.Access.newBuilder()
- .setPrivateAccess(Semanticdb.PrivateAccess.newBuilder())
- .build();
- }
-
- public static Semanticdb.Access publicAccess() {
- return Semanticdb.Access.newBuilder()
- .setPublicAccess(Semanticdb.PublicAccess.newBuilder())
- .build();
- }
-
- public static Semanticdb.Access protectedAccess() {
- return Semanticdb.Access.newBuilder()
- .setProtectedAccess(Semanticdb.ProtectedAccess.newBuilder())
- .build();
- }
-
- public static Semanticdb.Access privateWithinAccess(String symbol) {
- return Semanticdb.Access.newBuilder()
- .setPrivateWithinAccess(Semanticdb.PrivateWithinAccess.newBuilder().setSymbol(symbol))
- .build();
- }
-
- // SemanticDB Trees
-
- public static Semanticdb.Tree tree(Semanticdb.IdTree idTree) {
- return Semanticdb.Tree.newBuilder().setIdTree(idTree).build();
- }
-
- public static Semanticdb.IdTree idTree(String symbol) {
- return Semanticdb.IdTree.newBuilder().setSymbol(symbol).build();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.ApplyTree applyTree) {
- return Semanticdb.Tree.newBuilder().setApplyTree(applyTree).build();
- }
-
- public static Semanticdb.ApplyTree applyTree(
- Semanticdb.Tree function, Iterable arguments) {
- return Semanticdb.ApplyTree.newBuilder()
- .setFunction(function)
- .addAllArguments(arguments)
- .build();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.SelectTree selectTree) {
- return Semanticdb.Tree.newBuilder().setSelectTree(selectTree).build();
- }
-
- public static Semanticdb.SelectTree selectTree(
- Semanticdb.Tree qualifier, Semanticdb.IdTree idTree) {
- return Semanticdb.SelectTree.newBuilder().setQualifier(qualifier).setId(idTree).build();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.LiteralTree literalTree) {
- return Semanticdb.Tree.newBuilder().setLiteralTree(literalTree).build();
- }
-
- public static Semanticdb.LiteralTree literalTree(Semanticdb.Constant constant) {
- return Semanticdb.LiteralTree.newBuilder().setConstant(constant).build();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.AnnotationTree annotationTree) {
- return Semanticdb.Tree.newBuilder().setAnnotationTree(annotationTree).build();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.BinaryOperatorTree binaryOperatorTree) {
- return Semanticdb.Tree.newBuilder().setBinopTree(binaryOperatorTree).build();
- }
-
- public static Semanticdb.BinaryOperatorTree binopTree(
- Semanticdb.Tree lhs, Semanticdb.BinaryOperator operator, Semanticdb.Tree rhs) {
- return Semanticdb.BinaryOperatorTree.newBuilder()
- .setLhs(lhs)
- .setOp(operator)
- .setRhs(rhs)
- .build();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.UnaryOperatorTree unaryOperatorTree) {
- 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();
- }
-
- public static Semanticdb.Tree tree(Semanticdb.AssignTree assignTree) {
- return Semanticdb.Tree.newBuilder().setAssignTree(assignTree).build();
- }
-
- public static Semanticdb.AssignTree assignTree(Semanticdb.Tree lhs, Semanticdb.Tree rhs) {
- 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) {
- return Semanticdb.Constant.newBuilder()
- .setStringConstant(Semanticdb.StringConstant.newBuilder().setValue(value))
- .build();
- }
-
- public static Semanticdb.Constant doubleConst(Double value) {
- return Semanticdb.Constant.newBuilder()
- .setDoubleConstant(Semanticdb.DoubleConstant.newBuilder().setValue(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))
- .build();
- }
-
- public static Semanticdb.Constant longConst(Long value) {
- return Semanticdb.Constant.newBuilder()
- .setLongConstant(Semanticdb.LongConstant.newBuilder().setValue(value))
- .build();
- }
-
- public static Semanticdb.Constant intConst(Integer value) {
- return Semanticdb.Constant.newBuilder()
- .setIntConstant(Semanticdb.IntConstant.newBuilder().setValue(value))
- .build();
- }
-
- public static Semanticdb.Constant charConst(Character value) {
- return Semanticdb.Constant.newBuilder()
- .setCharConstant(Semanticdb.CharConstant.newBuilder().setValue(value))
- .build();
- }
-
- public static Semanticdb.Constant shortConst(Short value) {
- return Semanticdb.Constant.newBuilder()
- .setShortConstant(Semanticdb.ShortConstant.newBuilder().setValue(value))
- .build();
- }
-
- public static Semanticdb.Constant byteConst(Byte value) {
- return Semanticdb.Constant.newBuilder()
- .setByteConstant(Semanticdb.ByteConstant.newBuilder().setValue(value))
- .build();
- }
-
- public static Semanticdb.Constant booleanConst(Boolean value) {
- return Semanticdb.Constant.newBuilder()
- .setBooleanConstant(Semanticdb.BooleanConstant.newBuilder().setValue(value))
- .build();
- }
-}
diff --git a/semanticdb-java/src/main/protobuf/BUILD b/semanticdb-java/src/main/protobuf/BUILD
deleted file mode 100644
index 88669718b..000000000
--- a/semanticdb-java/src/main/protobuf/BUILD
+++ /dev/null
@@ -1,16 +0,0 @@
-load("@rules_java//java:defs.bzl", "java_proto_library")
-load("@rules_proto//proto:defs.bzl", "proto_library")
-
-package(
- default_visibility = ["//visibility:public"],
-)
-
-java_proto_library(
- name = "semanticdb_java_proto",
- deps = [":semanticdb_proto"],
-)
-
-proto_library(
- name = "semanticdb_proto",
- srcs = ["semanticdb.proto"]
-)
diff --git a/semanticdb-java/src/main/protobuf/semanticdb.proto b/semanticdb-java/src/main/protobuf/semanticdb.proto
deleted file mode 100644
index a671f4689..000000000
--- a/semanticdb-java/src/main/protobuf/semanticdb.proto
+++ /dev/null
@@ -1,468 +0,0 @@
-// Original source: https://github.com/scalameta/scalameta/blob/cf796cf2436b40494baf2bdc266623dc65264ad5/semanticdb/semanticdb/semanticdb.proto
-// Local modifications:
-// - Removes unused fields to minimize the amount of generated code.
-// - Adds SymbolInformation.documentation that is pending upstream approval.
-
-syntax = "proto3";
-
-package com.sourcegraph.semanticdb_javac;
-
-enum Schema {
- LEGACY = 0;
- SEMANTICDB3 = 3;
- SEMANTICDB4 = 4;
-}
-
-message TextDocuments {
- repeated TextDocument documents = 1;
-}
-
-message TextDocument {
- reserved 4, 8, 9;
- Schema schema = 1;
- string uri = 2;
- string text = 3;
- string md5 = 11;
- Language language = 10;
- repeated SymbolInformation symbols = 5;
- repeated SymbolOccurrence occurrences = 6;
- repeated Synthetic synthetics = 12;
-}
-
-enum Language {
- UNKNOWN_LANGUAGE = 0;
- SCALA = 1;
- JAVA = 2;
- KOTLIN = 3;
-}
-
-message Range {
- int32 start_line = 1;
- int32 start_character = 2;
- int32 end_line = 3;
- int32 end_character = 4;
-}
-
-message Signature {
- oneof sealed_value {
- ClassSignature class_signature = 1;
- MethodSignature method_signature = 2;
- TypeSignature type_signature = 3;
- ValueSignature value_signature = 4;
- }
-}
-
-message ClassSignature {
- Scope type_parameters = 1;
- repeated Type parents = 2;
- Scope declarations = 4;
-}
-
-message MethodSignature {
- Scope type_parameters = 1;
- repeated Scope parameter_lists = 2;
- Type return_type = 3;
- repeated Type throws = 4;
-}
-
-message TypeSignature {
- Scope type_parameters = 1;
- Type lower_bound = 2;
- Type upper_bound = 3;
-}
-
-message ValueSignature {
- Type tpe = 1;
-}
-
-message SymbolInformation {
- enum Kind {
- reserved 1, 2, 4, 5, 15, 16;
- UNKNOWN_KIND = 0;
- LOCAL = 19;
- FIELD = 20;
- METHOD = 3;
- CONSTRUCTOR = 21;
- MACRO = 6;
- TYPE = 7;
- PARAMETER = 8;
- SELF_PARAMETER = 17;
- TYPE_PARAMETER = 9;
- OBJECT = 10;
- PACKAGE = 11;
- PACKAGE_OBJECT = 12;
- CLASS = 13;
- TRAIT = 14;
- INTERFACE = 18;
- }
- enum Property {
- UNKNOWN_PROPERTY = 0;
- reserved 0x1;
- reserved 0x2;
- ABSTRACT = 0x4;
- FINAL = 0x8;
- SEALED = 0x10;
- IMPLICIT = 0x20;
- LAZY = 0x40;
- CASE = 0x80;
- COVARIANT = 0x100;
- CONTRAVARIANT = 0x200;
- VAL = 0x400;
- VAR = 0x800;
- STATIC = 0x1000;
- PRIMARY = 0x2000;
- ENUM = 0x4000;
- DEFAULT = 0x8000;
- }
- reserved 2, 6, 7, 8, 9, 10, 11, 12, 14;
- string symbol = 1;
- Language language = 16;
- Kind kind = 3;
- int32 properties = 4;
- string display_name = 5;
- // -- OUT OF SPEC -- //
- repeated AnnotationTree annotations = 13;
- // -- OUT OF SPEC -- //
- Signature signature = 17;
- Access access = 18;
- repeated string overridden_symbols = 19;
- Documentation documentation = 20;
- string enclosing_symbol = 15;
-
- // -- OUT OF SPEC -- //
- repeated string definition_relationships = 21;
- // -- OUT OF SPEC -- //
-}
-
-message Access {
- oneof sealed_value {
- PrivateAccess private_access = 1;
- PrivateThisAccess private_this_access = 2;
- PrivateWithinAccess private_within_access = 3;
- ProtectedAccess protected_access = 4;
- PublicAccess public_access = 7;
- }
-}
-
-message PrivateAccess {}
-
-message PrivateWithinAccess {
- string symbol = 1;
-}
-
-message PrivateThisAccess {
-}
-
-message ProtectedAccess {}
-
-message PublicAccess {}
-
-message Documentation {
- enum Format {
- HTML = 0;
- MARKDOWN = 1;
- JAVADOC = 2;
- SCALADOC = 3;
- KDOC = 4;
- }
- string message = 1;
- Format format = 2;
-}
-
-message SymbolOccurrence {
- enum Role {
- UNKNOWN_ROLE = 0;
- REFERENCE = 1;
- DEFINITION = 2;
- // NOTE: this role does not exist in the upstream SemanticDB spec.
- // WE added SYNTHETIC_DEFINITION fix the following scip-java issue:
- // https://github.com/sourcegraph/scip-java/issues/399
- SYNTHETIC_DEFINITION = 3;
- }
- Range range = 1;
- string symbol = 2;
- Role role = 3;
- // NOTE: this field does not exist in the upstream SemanticDB spec.
- // It is added to support SCIP's enclosing_range field.
- // This is the range of the nearest non-trivial enclosing AST node.
- optional Range enclosing_range = 4;
-}
-
-message Scope {
- repeated string symlinks = 1;
- repeated SymbolInformation hardlinks = 2;
-}
-
-message Type {
- reserved 1, 3, 4, 5, 6, 11, 12, 15, 16;
- oneof sealed_value {
- TypeRef type_ref = 2;
- SingleType single_type = 20;
- ThisType this_type = 21;
- SuperType super_type = 22;
- ConstantType constant_type = 23;
- IntersectionType intersection_type = 17;
- UnionType union_type = 18;
- WithType with_type = 19;
- StructuralType structural_type = 7;
- AnnotatedType annotated_type = 8;
- ExistentialType existential_type = 9;
- UniversalType universal_type = 10;
- ByNameType by_name_type = 13;
- RepeatedType repeated_type = 14;
- }
-}
-
-
-message TypeRef {
- Type prefix = 1;
- string symbol = 2;
- repeated Type type_arguments = 3;
-}
-
-message SingleType {
- Type prefix = 1;
- string symbol = 2;
-}
-
-message ThisType {
- string symbol = 1;
-}
-
-message SuperType {
- Type prefix = 1;
- string symbol = 2;
-}
-
-message ConstantType {
- Constant constant = 1;
-}
-
-message IntersectionType {
- repeated Type types = 1;
-}
-
-message UnionType {
- repeated Type types = 1;
-}
-
-message WithType {
- repeated Type types = 1;
-}
-
-message StructuralType {
- reserved 1, 2, 3;
- Type tpe = 4;
- Scope declarations = 5;
-}
-
-message AnnotatedType {
- reserved 2;
- repeated AnnotationTree annotations = 3;
- Type tpe = 1;
-}
-
-message ExistentialType {
- reserved 2;
- Type tpe = 1;
- Scope declarations = 3;
-}
-
-message UniversalType {
- reserved 1;
- Scope type_parameters = 3;
- Type tpe = 2;
-}
-
-message ByNameType {
- Type tpe = 1;
-}
-
-message RepeatedType {
- Type tpe = 1;
-}
-
-message Synthetic {
- Range range = 1;
- Tree tree = 2;
-}
-
-message Tree {
- oneof sealed_value {
- ApplyTree apply_tree = 1;
- FunctionTree function_tree = 2;
- IdTree id_tree = 3;
- LiteralTree literal_tree = 4;
- MacroExpansionTree macro_expansion_tree = 5;
- OriginalTree original_tree = 6;
- SelectTree select_tree = 7;
- TypeApplyTree type_apply_tree = 8;
- // -- OUT OF SPEC -- //
- AnnotationTree annotation_tree = 9;
- AssignTree assign_tree = 10;
- BinaryOperatorTree binop_tree = 11;
- UnaryOperatorTree unaryop_tree = 12;
- CastTree cast_tree = 13;
- // -- OUT OF SPEC -- //
- }
-}
-
-message ApplyTree {
- Tree function = 1;
- repeated Tree arguments = 2;
-}
-
-
-message FunctionTree {
- repeated IdTree parameters = 1;
- Tree body = 2;
-}
-
-message IdTree {
- string symbol = 1;
-}
-
-
-message LiteralTree {
- Constant constant = 1;
-}
-
-message MacroExpansionTree {
- Tree before_expansion = 1;
- Type tpe = 2;
-}
-
-message OriginalTree {
- Range range = 1;
-}
-
-message SelectTree {
- Tree qualifier = 1;
- IdTree id = 2;
-}
-
-message TypeApplyTree {
- Tree function = 1;
- repeated Type type_arguments = 2;
-}
-
-// -- OUT OF SPEC -- //
-message AnnotationTree {
- Type tpe = 1;
- repeated Tree parameters = 2;
-}
-
-
-message CastTree {
- Type tpe = 1;
- Tree value = 2;
-}
-
-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;
-}
-
-// 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 {
- oneof sealed_value {
- UnitConstant unit_constant = 1;
- BooleanConstant boolean_constant = 2;
- ByteConstant byte_constant = 3;
- ShortConstant short_constant = 4;
- CharConstant char_constant = 5;
- IntConstant int_constant = 6;
- LongConstant long_constant = 7;
- FloatConstant float_constant = 8;
- DoubleConstant double_constant = 9;
- StringConstant string_constant = 10;
- NullConstant null_constant = 11;
- }
-}
-
-message UnitConstant {
-}
-
-message BooleanConstant {
- bool value = 1;
-}
-
-message ByteConstant {
- int32 value = 1;
-}
-
-message ShortConstant {
- int32 value = 1;
-}
-
-message CharConstant {
- int32 value = 1;
-}
-
-message IntConstant {
- int32 value = 1;
-}
-
-message LongConstant {
- int64 value = 1;
-}
-
-message FloatConstant {
- float value = 1;
-}
-
-message DoubleConstant {
- double value = 1;
-}
-
-message StringConstant {
- string value = 1;
-}
-
-message NullConstant {
-}
diff --git a/semanticdb-javac/BUILD b/semanticdb-javac/BUILD
index 37a6e13f9..e7dad490c 100644
--- a/semanticdb-javac/BUILD
+++ b/semanticdb-javac/BUILD
@@ -34,7 +34,6 @@ java_library(
srcs = glob(["src/main/java/**/*.java"]),
resources = ["src/main/resources/META-INF/services/com.sun.source.util.Plugin"],
deps = [
- "//semanticdb-java/src/main/protobuf:semanticdb_java_proto",
"//semanticdb-java",
":javac-import",
],
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipOccurrences.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipOccurrences.java
new file mode 100644
index 000000000..d4b29e913
--- /dev/null
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipOccurrences.java
@@ -0,0 +1,66 @@
+package com.sourcegraph.semanticdb_javac;
+
+import com.sourcegraph.Scip;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Helpers for deduplicating SCIP {@link Scip.Occurrence} entries by their {@code (symbol, range,
+ * roles)} key. Variants that differ only in whether {@code enclosing_range} is set are collapsed,
+ * preferring the one that carries the enclosing range.
+ */
+final class ScipOccurrences {
+
+ private ScipOccurrences() {}
+
+ /** Returns a new list with duplicate occurrences collapsed in insertion order. */
+ static List deduplicate(List occurrences) {
+ LinkedHashMap out = new LinkedHashMap<>();
+ for (Scip.Occurrence occ : occurrences) put(out, occ);
+ return new ArrayList<>(out.values());
+ }
+
+ /** Inserts {@code occ} into {@code out}, collapsing duplicates by {@link Key}. */
+ static void put(LinkedHashMap out, Scip.Occurrence occ) {
+ Key key = Key.of(occ);
+ Scip.Occurrence existing = out.get(key);
+ if (existing == null) {
+ out.put(key, occ);
+ return;
+ }
+ if (existing.getEnclosingRangeCount() == 0 && occ.getEnclosingRangeCount() > 0) {
+ out.put(key, occ);
+ }
+ }
+
+ static final class Key {
+ final String symbol;
+ final List range;
+ final int roles;
+
+ private Key(String symbol, List range, int roles) {
+ this.symbol = symbol;
+ this.range = range;
+ this.roles = roles;
+ }
+
+ static Key of(Scip.Occurrence occ) {
+ return new Key(occ.getSymbol(), occ.getRangeList(), occ.getSymbolRoles());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Key)) return false;
+ Key other = (Key) o;
+ return roles == other.roles && symbol.equals(other.symbol) && range.equals(other.range);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(symbol, range, roles);
+ }
+ }
+}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipRange.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipRange.java
new file mode 100644
index 000000000..96132043f
--- /dev/null
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipRange.java
@@ -0,0 +1,41 @@
+package com.sourcegraph.semanticdb_javac;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Lightweight value type for source ranges produced by {@link ScipVisitor}.
+ *
+ * Coordinates are zero-based and follow the SCIP convention (line + character, end-exclusive
+ * character). Convertible directly to SCIP's {@code repeated int32 range} representation via {@link
+ * #asScipRange()}.
+ */
+final class ScipRange {
+ final int startLine;
+ final int startCharacter;
+ final int endLine;
+ final int endCharacter;
+
+ ScipRange(int startLine, int startCharacter, int endLine, int endCharacter) {
+ this.startLine = startLine;
+ this.startCharacter = startCharacter;
+ this.endLine = endLine;
+ this.endCharacter = endCharacter;
+ }
+
+ /** Returns a copy with adjusted start/end characters (used to correct for tab-expansion). */
+ ScipRange withCharacters(int startCharacter, int endCharacter) {
+ return new ScipRange(startLine, startCharacter, endLine, endCharacter);
+ }
+
+ /**
+ * Encodes the range using SCIP's compact {@code repeated int32 range} layout: 3 ints when the
+ * range fits on a single line, 4 ints otherwise.
+ */
+ List asScipRange() {
+ if (startLine == endLine) {
+ return Arrays.asList(startLine, startCharacter, endCharacter);
+ }
+ return Arrays.asList(startLine, startCharacter, endLine, endCharacter);
+ }
+}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipRole.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipRole.java
new file mode 100644
index 000000000..6ddbd2344
--- /dev/null
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipRole.java
@@ -0,0 +1,11 @@
+package com.sourcegraph.semanticdb_javac;
+
+/**
+ * Minimal role enum used by {@link ScipVisitor} when emitting SCIP occurrences. Mirrors the subset
+ * of {@code Semanticdb.SymbolOccurrence.Role} that the direct-to-SCIP visitor cares about.
+ */
+enum ScipRole {
+ DEFINITION,
+ REFERENCE,
+ SYNTHETIC_DEFINITION
+}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipShardWriter.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipShardWriter.java
new file mode 100644
index 000000000..5bf5df35b
--- /dev/null
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipShardWriter.java
@@ -0,0 +1,119 @@
+package com.sourcegraph.semanticdb_javac;
+
+import com.sourcegraph.Scip;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Writes and merges per-source SCIP shards produced by the compiler plugin.
+ *
+ * Each source file produces a self-contained {@link Scip.Index} shard containing a single {@link
+ * Scip.Document}. When a shard already exists on disk (e.g. during annotation processing rounds),
+ * the new document is merged into the existing one, deduplicating occurrences, symbols and
+ * relationships.
+ */
+public final class ScipShardWriter {
+
+ private ScipShardWriter() {}
+
+ /**
+ * Writes the given {@code shard} to {@code output}, creating parent directories as needed. If
+ * {@code output} already exists, the existing shard is parsed and merged with the new one.
+ */
+ public static void writeOrMerge(Path output, Scip.Index shard) throws IOException {
+ Files.createDirectories(output.getParent());
+ if (Files.exists(output)) {
+ Scip.Index existing;
+ try (InputStream is = Files.newInputStream(output)) {
+ existing = Scip.Index.parseFrom(is);
+ }
+ shard = merge(existing, shard);
+ }
+ Files.write(output, shard.toByteArray());
+ }
+
+ /**
+ * Merges two SCIP shards by combining their document lists. Documents that share a {@code
+ * relative_path} have their occurrences, symbols and external symbols deduplicated.
+ */
+ static Scip.Index merge(Scip.Index a, Scip.Index b) {
+ Scip.Index.Builder builder = Scip.Index.newBuilder();
+ if (b.hasMetadata()) {
+ builder.setMetadata(b.getMetadata());
+ } else if (a.hasMetadata()) {
+ builder.setMetadata(a.getMetadata());
+ }
+
+ LinkedHashMap byPath = new LinkedHashMap<>();
+ for (Scip.Document doc : a.getDocumentsList()) {
+ byPath.put(doc.getRelativePath(), doc);
+ }
+ for (Scip.Document doc : b.getDocumentsList()) {
+ Scip.Document existing = byPath.get(doc.getRelativePath());
+ if (existing == null) {
+ byPath.put(doc.getRelativePath(), doc);
+ } else {
+ byPath.put(doc.getRelativePath(), mergeDocuments(existing, doc));
+ }
+ }
+ builder.addAllDocuments(byPath.values());
+
+ // External symbols: deduplicate by symbol string. Last writer wins to keep latest data.
+ LinkedHashMap externals = new LinkedHashMap<>();
+ for (Scip.SymbolInformation s : a.getExternalSymbolsList()) externals.put(s.getSymbol(), s);
+ for (Scip.SymbolInformation s : b.getExternalSymbolsList()) externals.put(s.getSymbol(), s);
+ builder.addAllExternalSymbols(externals.values());
+
+ return builder.build();
+ }
+
+ private static Scip.Document mergeDocuments(Scip.Document a, Scip.Document b) {
+ Scip.Document.Builder builder = b.toBuilder().clearOccurrences().clearSymbols();
+ // Use the most recent metadata for language/relative_path/text/encoding which already
+ // come from b via toBuilder().
+
+ // Deduplicate occurrences by (range, symbol, roles). Variants that differ only in
+ // enclosing_range get collapsed, preferring the one that carries the enclosing range.
+ LinkedHashMap occurrences = new LinkedHashMap<>();
+ for (Scip.Occurrence occ : a.getOccurrencesList()) ScipOccurrences.put(occurrences, occ);
+ for (Scip.Occurrence occ : b.getOccurrencesList()) ScipOccurrences.put(occurrences, occ);
+ builder.addAllOccurrences(occurrences.values());
+
+ // Deduplicate symbols by symbol string; merge relationships and documentation.
+ Map bySymbol = new LinkedHashMap<>();
+ for (Scip.SymbolInformation info : a.getSymbolsList()) bySymbol.put(info.getSymbol(), info);
+ for (Scip.SymbolInformation info : b.getSymbolsList()) {
+ Scip.SymbolInformation existing = bySymbol.get(info.getSymbol());
+ bySymbol.put(info.getSymbol(), existing == null ? info : mergeSymbol(existing, info));
+ }
+ builder.addAllSymbols(bySymbol.values());
+
+ return builder.build();
+ }
+
+ private static Scip.SymbolInformation mergeSymbol(
+ Scip.SymbolInformation a, Scip.SymbolInformation b) {
+ Scip.SymbolInformation.Builder builder = b.toBuilder();
+ // Merge relationships, deduplicating by structural equality with deterministic ordering.
+ Map rels = new LinkedHashMap<>();
+ for (Scip.Relationship r : a.getRelationshipsList()) rels.put(r, r);
+ for (Scip.Relationship r : b.getRelationshipsList()) rels.put(r, r);
+ builder.clearRelationships().addAllRelationships(rels.values());
+
+ // Merge documentation, preserving order and avoiding duplicates.
+ List docs = new ArrayList<>(a.getDocumentationList());
+ for (String d : b.getDocumentationList()) {
+ if (!docs.contains(d)) docs.add(d);
+ }
+ builder.clearDocumentation().addAllDocumentation(docs);
+
+ return builder.build();
+ }
+}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipSignatureFormatter.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipSignatureFormatter.java
new file mode 100644
index 000000000..91dd63892
--- /dev/null
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipSignatureFormatter.java
@@ -0,0 +1,288 @@
+package com.sourcegraph.semanticdb_javac;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.IntersectionType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * Formats a Java {@link Element} as a human-readable declaration string suitable for SCIP's {@code
+ * SymbolInformation.signature_documentation.text}.
+ *
+ * This is a port of the Java-relevant parts of {@code SignatureFormatter} that runs directly
+ * over javac's {@link Element}/{@link TypeMirror} APIs, eliminating the need to round-trip through
+ * SemanticDB signatures.
+ */
+public final class ScipSignatureFormatter {
+
+ private final Element sym;
+
+ public ScipSignatureFormatter(Element sym) {
+ this.sym = sym;
+ }
+
+ /** Returns the formatted signature, or {@code ""} if {@link #sym} has no meaningful signature. */
+ public String formatSymbol() {
+ StringBuilder out = new StringBuilder();
+ switch (sym.getKind()) {
+ case CLASS:
+ case INTERFACE:
+ case ANNOTATION_TYPE:
+ case ENUM:
+ formatType(out, (TypeElement) sym);
+ break;
+ case CONSTRUCTOR:
+ case METHOD:
+ formatExecutable(out, (ExecutableElement) sym);
+ break;
+ case FIELD:
+ case ENUM_CONSTANT:
+ case PARAMETER:
+ case LOCAL_VARIABLE:
+ case EXCEPTION_PARAMETER:
+ case RESOURCE_VARIABLE:
+ formatVariable(out, (VariableElement) sym);
+ break;
+ case TYPE_PARAMETER:
+ formatTypeParameter(out, (TypeParameterElement) sym);
+ break;
+ default:
+ return "";
+ }
+ return out.toString();
+ }
+
+ private static void formatAnnotations(StringBuilder out, Element element) {
+ for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+ out.append('@').append(simpleName(mirror.getAnnotationType())).append('\n');
+ }
+ }
+
+ private static String simpleName(TypeMirror t) {
+ if (t instanceof DeclaredType) {
+ Element e = ((DeclaredType) t).asElement();
+ return e.getSimpleName().toString();
+ }
+ return t.toString();
+ }
+
+ private static void formatModifiers(StringBuilder out, Set modifiers) {
+ for (Modifier m : modifiers) {
+ out.append(m.toString()).append(' ');
+ }
+ }
+
+ private void formatType(StringBuilder out, TypeElement type) {
+ formatAnnotations(out, type);
+ formatModifiers(out, type.getModifiers());
+ switch (type.getKind()) {
+ case ENUM:
+ out.append("enum ");
+ break;
+ case INTERFACE:
+ out.append("interface ");
+ break;
+ case ANNOTATION_TYPE:
+ out.append("@interface ");
+ break;
+ case CLASS:
+ default:
+ out.append("class ");
+ break;
+ }
+ out.append(type.getSimpleName());
+ formatTypeParameters(out, type.getTypeParameters());
+
+ TypeMirror superclass = type.getSuperclass();
+ if (superclass.getKind() != TypeKind.NONE
+ && !isJavaLangObject(superclass)
+ && type.getKind() != ElementKind.INTERFACE) {
+ out.append(" extends ");
+ formatTypeMirror(out, superclass);
+ }
+
+ List extends TypeMirror> interfaces = type.getInterfaces();
+ if (!interfaces.isEmpty()) {
+ out.append(type.getKind() == ElementKind.INTERFACE ? " extends " : " implements ");
+ formatJoin(out, interfaces, ", ");
+ }
+ }
+
+ private void formatExecutable(StringBuilder out, ExecutableElement method) {
+ formatAnnotations(out, method);
+ formatModifiers(out, method.getModifiers());
+ if (!method.getTypeParameters().isEmpty()) {
+ formatTypeParameters(out, method.getTypeParameters());
+ out.append(' ');
+ }
+ if (method.getKind() != ElementKind.CONSTRUCTOR) {
+ formatTypeMirror(out, method.getReturnType());
+ out.append(' ');
+ out.append(method.getSimpleName());
+ } else {
+ // Constructor: name = enclosing class simple name
+ out.append(method.getEnclosingElement().getSimpleName());
+ }
+ out.append('(');
+ Iterator extends VariableElement> it = method.getParameters().iterator();
+ while (it.hasNext()) {
+ VariableElement p = it.next();
+ formatTypeMirror(out, p.asType());
+ out.append(' ').append(p.getSimpleName());
+ if (it.hasNext()) out.append(", ");
+ }
+ out.append(')');
+ List extends TypeMirror> thrown = method.getThrownTypes();
+ if (!thrown.isEmpty()) {
+ out.append(" throws ");
+ formatJoin(out, thrown, ", ");
+ }
+ }
+
+ private void formatVariable(StringBuilder out, VariableElement variable) {
+ formatAnnotations(out, variable);
+ formatModifiers(out, variable.getModifiers());
+ if (variable.getKind() == ElementKind.ENUM_CONSTANT) {
+ out.append(variable.getSimpleName());
+ } else {
+ formatTypeMirror(out, variable.asType());
+ out.append(' ').append(variable.getSimpleName());
+ }
+ }
+
+ private void formatTypeParameter(StringBuilder out, TypeParameterElement tp) {
+ out.append(tp.getSimpleName());
+ List extends TypeMirror> bounds = tp.getBounds();
+ if (!bounds.isEmpty()) {
+ // Skip implicit `extends Object`.
+ if (bounds.size() != 1 || !isJavaLangObject(bounds.get(0))) {
+ out.append(" extends ");
+ formatJoin(out, bounds, " & ");
+ }
+ }
+ }
+
+ private void formatTypeParameters(
+ StringBuilder out, List extends TypeParameterElement> typeParameters) {
+ if (typeParameters.isEmpty()) return;
+ out.append('<');
+ Iterator extends TypeParameterElement> it = typeParameters.iterator();
+ while (it.hasNext()) {
+ formatTypeParameter(out, it.next());
+ if (it.hasNext()) out.append(", ");
+ }
+ out.append('>');
+ }
+
+ private void formatJoin(StringBuilder out, List extends TypeMirror> types, String separator) {
+ Iterator extends TypeMirror> it = types.iterator();
+ while (it.hasNext()) {
+ formatTypeMirror(out, it.next());
+ if (it.hasNext()) out.append(separator);
+ }
+ }
+
+ private void formatTypeMirror(StringBuilder out, TypeMirror type) {
+ type.accept(new TypePrinter(), out);
+ }
+
+ private static boolean isJavaLangObject(TypeMirror type) {
+ if (!(type instanceof DeclaredType)) return false;
+ Element e = ((DeclaredType) type).asElement();
+ return e instanceof TypeElement
+ && ((TypeElement) e).getQualifiedName().contentEquals("java.lang.Object");
+ }
+
+ /** Prints a TypeMirror using simple-names + type arguments + array brackets. */
+ private static final class TypePrinter extends SimpleTypeVisitor8 {
+
+ @Override
+ public Void visitDeclared(DeclaredType t, StringBuilder out) {
+ out.append(simpleName(t));
+ List extends TypeMirror> args = t.getTypeArguments();
+ if (!args.isEmpty()) {
+ out.append('<');
+ Iterator extends TypeMirror> it = args.iterator();
+ while (it.hasNext()) {
+ visit(it.next(), out);
+ if (it.hasNext()) out.append(", ");
+ }
+ out.append('>');
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitArray(ArrayType t, StringBuilder out) {
+ visit(t.getComponentType(), out);
+ out.append("[]");
+ return null;
+ }
+
+ @Override
+ public Void visitPrimitive(PrimitiveType t, StringBuilder out) {
+ out.append(t.getKind().name().toLowerCase());
+ return null;
+ }
+
+ @Override
+ public Void visitTypeVariable(TypeVariable t, StringBuilder out) {
+ out.append(t.asElement().getSimpleName());
+ return null;
+ }
+
+ @Override
+ public Void visitWildcard(WildcardType t, StringBuilder out) {
+ out.append('?');
+ if (t.getExtendsBound() != null) {
+ out.append(" extends ");
+ visit(t.getExtendsBound(), out);
+ } else if (t.getSuperBound() != null) {
+ out.append(" super ");
+ visit(t.getSuperBound(), out);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitIntersection(IntersectionType t, StringBuilder out) {
+ Iterator extends TypeMirror> it = t.getBounds().iterator();
+ while (it.hasNext()) {
+ visit(it.next(), out);
+ if (it.hasNext()) out.append(" & ");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitNoType(NoType t, StringBuilder out) {
+ if (t.getKind() == TypeKind.VOID) {
+ out.append("void");
+ }
+ return null;
+ }
+
+ @Override
+ protected Void defaultAction(TypeMirror t, StringBuilder out) {
+ out.append(t.toString());
+ return null;
+ }
+ }
+}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipSymbols.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipSymbols.java
new file mode 100644
index 000000000..736b287cd
--- /dev/null
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipSymbols.java
@@ -0,0 +1,46 @@
+package com.sourcegraph.semanticdb_javac;
+
+/**
+ * Helpers for emitting SCIP symbol strings from the compiler plugin.
+ *
+ * Because the compiler plugin does not know the final Maven coordinates ({@code
+ * groupId:artifactId:version}) at compile time, it emits global symbols using a sentinel
+ * placeholder scheme that is rewritten by the aggregator to its final form:
+ *
+ *
+ * ". . . . " + <semanticdb-style descriptor path>
+ * -> "scip-java maven <groupId> <artifactId> <version> <descriptor path>"
+ *
+ *
+ * Local symbols are emitted using the canonical SCIP {@code "local N"} form (with the space) and
+ * are not rewritten by the aggregator.
+ */
+public final class ScipSymbols {
+
+ /**
+ * Prefix marking a global symbol whose package coordinates must be filled in by the aggregator.
+ * The trailing space matches the SCIP grammar requirement of separating the scheme from the
+ * package fields.
+ */
+ public static final String PLACEHOLDER_PREFIX = ". . . . ";
+
+ private ScipSymbols() {}
+
+ /**
+ * Converts a SemanticDB-style symbol string (as produced by {@link GlobalSymbolsCache} and {@link
+ * LocalSymbolsCache}) into the SCIP symbol form expected by the aggregator.
+ *
+ *
+ * - Empty strings stay empty.
+ *
- Local symbols of the form {@code "local42"} become {@code "local 42"}.
+ *
- Everything else is prefixed with {@link #PLACEHOLDER_PREFIX}.
+ *
+ */
+ public static String fromSemanticdbSymbol(String symbol) {
+ if (symbol == null || symbol.isEmpty()) return "";
+ if (SemanticdbSymbols.isLocal(symbol)) {
+ return "local " + symbol.substring("local".length());
+ }
+ return PLACEHOLDER_PREFIX + symbol;
+ }
+}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipVisitor.java
similarity index 56%
rename from semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java
rename to semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipVisitor.java
index 3a24aa885..11f487832 100644
--- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/ScipVisitor.java
@@ -1,60 +1,58 @@
package com.sourcegraph.semanticdb_javac;
-import com.sun.source.util.SourcePositions;
-import com.sun.source.util.Trees;
-import com.sun.source.util.TreePathScanner;
-import com.sun.source.util.TreePath;
+import com.sourcegraph.Scip;
+import com.sun.source.tree.AnnotatedTypeTree;
+import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.tree.MemberReferenceTree;
+import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
-import com.sun.source.tree.VariableTree;
-import com.sun.source.tree.ClassTree;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.MethodTree;
import com.sun.source.tree.LineMap;
-import com.sun.source.tree.ExpressionTree;
-import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MemberSelectTree;
-import com.sun.source.tree.PackageTree;
-import com.sun.source.tree.TypeCastTree;
-import com.sun.source.tree.TypeParameterTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.ParameterizedTypeTree;
-import com.sun.source.tree.AnnotatedTypeTree;
-
-import javax.tools.Diagnostic;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.NoType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.util.Types;
-import javax.lang.model.util.Elements;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolInformation.Kind;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolInformation.Property;
-import com.sourcegraph.semanticdb_javac.Semanticdb.SymbolOccurrence.Role;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.TypeParameterTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import com.sun.source.util.Trees;
import java.io.IOException;
import java.nio.file.Path;
-import java.util.List;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
-import java.util.HashSet;
-import java.util.Set;
import java.util.Objects;
import java.util.Optional;
-import java.util.Iterator;
-import java.security.NoSuchAlgorithmException;
+import java.util.Set;
import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
-import static com.sourcegraph.semanticdb_javac.SemanticdbBuilders.*;
-
-/** Walks the AST of a typechecked compilation unit and generates a SemanticDB TextDocument. */
-public class SemanticdbVisitor extends TreePathScanner {
+/**
+ * Walks the AST of a typechecked compilation unit and generates a {@link Scip.Document} directly.
+ *
+ * Symbols are produced through {@link GlobalSymbolsCache} and then translated to the
+ * placeholder SCIP form via {@link ScipSymbols#fromSemanticdbSymbol(String)}. Signature
+ * documentation is produced by {@link ScipSignatureFormatter} directly from javac's element model.
+ */
+public final class ScipVisitor extends TreePathScanner {
private final GlobalSymbolsCache globals;
private final LocalSymbolsCache locals;
@@ -63,146 +61,249 @@ public class SemanticdbVisitor extends TreePathScanner {
private final CompilationUnitTree compUnitTree;
private final Elements elements;
private final SemanticdbJavacOptions options;
- private final ArrayList occurrences;
- private final ArrayList symbolInfos;
- private String source;
- private String uri;
-
+ private final ArrayList occurrences;
+ private final LinkedHashMap symbols;
+ private final String source;
+ private final String relativePath;
private final LinkedHashMap nodes;
- public SemanticdbVisitor(
+ public ScipVisitor(
GlobalSymbolsCache globals,
CompilationUnitTree compUnitTree,
SemanticdbJavacOptions options,
Types types,
Trees trees,
Elements elements) {
- this.globals = globals; // Reused cache between compilation units.
- this.locals = new LocalSymbolsCache(); // Fresh cache per compilation unit.
+ this.globals = globals;
+ this.locals = new LocalSymbolsCache();
this.options = options;
this.types = types;
this.elements = elements;
this.trees = trees;
this.compUnitTree = compUnitTree;
this.occurrences = new ArrayList<>();
- this.symbolInfos = new ArrayList<>();
- this.source = semanticdbText();
- this.uri = semanticdbUri(compUnitTree, options);
+ this.symbols = new LinkedHashMap<>();
+ this.source = sourceText(compUnitTree);
+ this.relativePath = sourceRelativePath(compUnitTree, options);
this.nodes = new LinkedHashMap<>();
}
- public Semanticdb.TextDocument buildTextDocument(CompilationUnitTree tree) {
- this.scan(tree, null); // Trigger recursive AST traversal to collect SemanticDB information.
-
+ /** Builds a single-document {@link Scip.Index} shard for the given compilation unit. */
+ public Scip.Index buildShard(CompilationUnitTree tree) {
+ this.scan(tree, null);
resolveNodes();
- return Semanticdb.TextDocument.newBuilder()
- .setSchema(Semanticdb.Schema.SEMANTICDB4)
- .setLanguage(Semanticdb.Language.JAVA)
- .setUri(uri)
- .setText(options.includeText ? this.source : "")
- .setMd5(semanticdbMd5())
- .addAllOccurrences(occurrences)
- .addAllSymbols(symbolInfos)
- .build();
+ Scip.Document.Builder document =
+ Scip.Document.newBuilder()
+ .setRelativePath(relativePath)
+ .setLanguage(LANGUAGE_JAVA);
+ if (options.includeText) {
+ document.setText(source);
+ }
+ document.addAllOccurrences(ScipOccurrences.deduplicate(occurrences));
+ document.addAllSymbols(symbols.values());
+
+ return Scip.Index.newBuilder().addDocuments(document).build();
}
- private Optional emitSymbolOccurrence(
- Element sym, Tree tree, Name name, Role role, CompilerRange kind) {
+ /** SCIP {@code Document.language} value for Java sources. */
+ static final String LANGUAGE_JAVA = "java";
+
+ // ==========================
+ // Symbol/occurrence emission
+ // ==========================
+
+ private Optional emitSymbolOccurrence(
+ Element sym, Tree tree, Name name, ScipRole role, CompilerRange kind) {
if (sym == null || name == null) return Optional.empty();
- Optional range = semanticdbRange(tree, kind, sym, name.toString());
- if (role == Role.DEFINITION) {
- emitSymbolOccurrence(sym, range, role, computeEnclosingRange(tree));
- // Only emit SymbolInformation for symbols that are defined in this compilation unit.
+ Optional range = scipRangeOf(tree, kind, sym, name.toString());
+ if (role == ScipRole.DEFINITION) {
+ emitOccurrence(sym, range, role, computeEnclosingRange(tree));
emitSymbolInformation(sym, tree);
return range;
}
- emitSymbolOccurrence(sym, range, role, Optional.empty());
+ emitOccurrence(sym, range, role, Optional.empty());
return range;
}
- private void emitSymbolOccurrence(
+ private void emitOccurrence(
Element sym,
- Optional range,
- Role role,
- Optional enclosingRange) {
- if (sym == null) return;
- Optional occ =
- semanticdbOccurrence(sym, range, role, enclosingRange);
- occ.ifPresent(occurrences::add);
+ Optional range,
+ ScipRole role,
+ Optional enclosingRange) {
+ if (sym == null || !range.isPresent()) return;
+ String semanticdbSymbol = semanticdbSymbol(sym);
+ if (semanticdbSymbol.equals(SemanticdbSymbols.NONE)) return;
+
+ Scip.Occurrence.Builder occ =
+ Scip.Occurrence.newBuilder()
+ .addAllRange(range.get().asScipRange())
+ .setSymbol(ScipSymbols.fromSemanticdbSymbol(semanticdbSymbol))
+ .setSymbolRoles(scipRole(role));
+ enclosingRange.ifPresent(r -> occ.addAllEnclosingRange(r.asScipRange()));
+ occurrences.add(occ.build());
}
private void emitSymbolInformation(Element sym, Tree tree) {
- String symbol = semanticdbSymbol(sym);
- Semanticdb.SymbolInformation.Builder builder = symbolInformation(symbol);
- Semanticdb.Documentation documentation = semanticdbDocumentation(tree);
- if (documentation != null) builder.setDocumentation(documentation);
- Semanticdb.Signature signature = semanticdbSignature(sym);
- if (signature != null) builder.setSignature(signature);
- if (SemanticdbSymbols.isLocal(symbol)) {
+ String semanticdbSymbol = semanticdbSymbol(sym);
+ if (semanticdbSymbol.equals(SemanticdbSymbols.NONE)) return;
+
+ Scip.SymbolInformation.Builder builder =
+ Scip.SymbolInformation.newBuilder()
+ .setSymbol(ScipSymbols.fromSemanticdbSymbol(semanticdbSymbol))
+ .setDisplayName(sym.getSimpleName().toString())
+ .setKind(scipKind(sym));
+
+ if (SemanticdbSymbols.isLocal(semanticdbSymbol)) {
String enclosingSymbol = semanticdbSymbol(sym.getEnclosingElement());
- if (enclosingSymbol != null) builder.setEnclosingSymbol(enclosingSymbol);
+ if (enclosingSymbol != null && !enclosingSymbol.equals(SemanticdbSymbols.NONE)) {
+ builder.setEnclosingSymbol(ScipSymbols.fromSemanticdbSymbol(enclosingSymbol));
+ }
}
- List annotations =
- new SemanticdbTrees(globals, locals, uri, types, trees, nodes).annotations(tree);
- if (annotations != null) builder.addAllAnnotations(annotations);
+ String documentation = semanticdbDocumentation(tree);
+ if (documentation != null && !documentation.isEmpty()) {
+ builder.addDocumentation(documentation);
+ }
- builder
- .setProperties(semanticdbSymbolInfoProperties(sym))
- .setDisplayName(sym.getSimpleName().toString())
- .setAccess(semanticdbAccess(sym));
+ String signature = new ScipSignatureFormatter(sym).formatSymbol();
+ if (!signature.isEmpty()) {
+ builder.setSignatureDocumentation(
+ Scip.Document.newBuilder()
+ .setLanguage(LANGUAGE_JAVA)
+ .setRelativePath(relativePath)
+ .setText(signature));
+ }
+
+ boolean supportsReferenceRel = supportsReferenceRelationship(sym);
switch (sym.getKind()) {
case ENUM:
case CLASS:
- builder.setKind(Kind.CLASS);
- builder.addAllOverriddenSymbols(semanticdbParentSymbols((TypeElement) sym));
- break;
case INTERFACE:
case ANNOTATION_TYPE:
- builder.setKind(Kind.INTERFACE);
- builder.addAllOverriddenSymbols(semanticdbParentSymbols((TypeElement) sym));
- break;
- case FIELD:
- builder.setKind(Kind.FIELD);
+ addParentRelationships(builder, (TypeElement) sym, supportsReferenceRel);
break;
case METHOD:
- builder.setKind(Kind.METHOD);
- builder.addAllOverriddenSymbols(
+ for (String overridden :
semanticdbOverrides(
- (ExecutableElement) sym, sym.getEnclosingElement(), new HashSet<>()));
- break;
- case CONSTRUCTOR:
- builder.setKind(Kind.CONSTRUCTOR);
- break;
- case TYPE_PARAMETER:
- builder.setKind(Kind.TYPE_PARAMETER);
+ (ExecutableElement) sym, sym.getEnclosingElement(), new HashSet<>())) {
+ if (isIgnoredOverriddenSymbol(overridden)) continue;
+ builder.addRelationships(
+ Scip.Relationship.newBuilder()
+ .setSymbol(ScipSymbols.fromSemanticdbSymbol(overridden))
+ .setIsImplementation(true)
+ .setIsReference(supportsReferenceRel));
+ }
break;
- case ENUM_CONSTANT: // overwrite previous value here
- String args =
- ((NewClassTree) ((VariableTree) tree).getInitializer())
- .getArguments().stream()
- .map(ExpressionTree::toString)
- .collect(Collectors.joining(", "));
- if (!args.isEmpty())
- builder.setDisplayName(sym.getSimpleName().toString() + "(" + args + ")");
+ case ENUM_CONSTANT:
+ if (tree instanceof VariableTree && ((VariableTree) tree).getInitializer() != null) {
+ String args =
+ ((NewClassTree) ((VariableTree) tree).getInitializer())
+ .getArguments().stream()
+ .map(ExpressionTree::toString)
+ .collect(Collectors.joining(", "));
+ if (!args.isEmpty()) {
+ builder.setDisplayName(sym.getSimpleName().toString() + "(" + args + ")");
+ }
+ }
break;
- case LOCAL_VARIABLE:
- builder.setKind(Kind.LOCAL);
+ default:
break;
}
- Semanticdb.SymbolInformation info = builder.build();
+ // Deduplicate by symbol; last write wins so newly discovered metadata takes precedence.
+ symbols.put(builder.getSymbol(), builder.build());
+ }
+
+ private void addParentRelationships(
+ Scip.SymbolInformation.Builder builder, TypeElement sym, boolean supportsReferenceRel) {
+ for (String parent : semanticdbParentSymbols(sym)) {
+ if (isIgnoredOverriddenSymbol(parent)) continue;
+ builder.addRelationships(
+ Scip.Relationship.newBuilder()
+ .setSymbol(ScipSymbols.fromSemanticdbSymbol(parent))
+ .setIsImplementation(true)
+ .setIsReference(supportsReferenceRel));
+ }
+ }
+
+ private static boolean isIgnoredOverriddenSymbol(String symbol) {
+ return symbol.equals("java/lang/Object#");
+ }
+
+ private static boolean supportsReferenceRelationship(Element sym) {
+ switch (sym.getKind()) {
+ case INTERFACE:
+ case CLASS:
+ case ANNOTATION_TYPE:
+ case ENUM:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ // =================================================
+ // Role / kind translation for SCIP emission.
+ // =================================================
+
+ private static int scipRole(ScipRole role) {
+ if (role == ScipRole.DEFINITION || role == ScipRole.SYNTHETIC_DEFINITION) {
+ return Scip.SymbolRole.Definition_VALUE;
+ }
+ return 0;
+ }
+
+ private static Scip.SymbolInformation.Kind scipKind(Element sym) {
+ Set modifiers = sym.getModifiers();
+ boolean isStatic = modifiers.contains(Modifier.STATIC);
+ // A `default` interface method has both ABSTRACT and DEFAULT modifiers; treat it as non-abstract.
+ boolean isAbstract =
+ modifiers.contains(Modifier.ABSTRACT) && !modifiers.contains(Modifier.DEFAULT);
- symbolInfos.add(info);
+ switch (sym.getKind()) {
+ case ENUM:
+ return Scip.SymbolInformation.Kind.Enum;
+ case ENUM_CONSTANT:
+ return Scip.SymbolInformation.Kind.EnumMember;
+ case CLASS:
+ return Scip.SymbolInformation.Kind.Class;
+ case INTERFACE:
+ case ANNOTATION_TYPE:
+ return Scip.SymbolInformation.Kind.Interface;
+ case FIELD:
+ return isStatic
+ ? Scip.SymbolInformation.Kind.StaticField
+ : Scip.SymbolInformation.Kind.Field;
+ case CONSTRUCTOR:
+ return Scip.SymbolInformation.Kind.Constructor;
+ case METHOD:
+ if (isStatic) return Scip.SymbolInformation.Kind.StaticMethod;
+ if (isAbstract) return Scip.SymbolInformation.Kind.AbstractMethod;
+ return Scip.SymbolInformation.Kind.Method;
+ case TYPE_PARAMETER:
+ return Scip.SymbolInformation.Kind.TypeParameter;
+ case LOCAL_VARIABLE:
+ case EXCEPTION_PARAMETER:
+ case RESOURCE_VARIABLE:
+ return Scip.SymbolInformation.Kind.Variable;
+ case PARAMETER:
+ return Scip.SymbolInformation.Kind.Parameter;
+ case PACKAGE:
+ return Scip.SymbolInformation.Kind.Package;
+ default:
+ return Scip.SymbolInformation.Kind.UnspecifiedKind;
+ }
}
+ // ===========================================
+ // Node resolution and traversal (unchanged from SemanticdbVisitor)
+ // ===========================================
+
void resolveNodes() {
- // ignore parts of NewClassTree. It would cause references to classes in addition to references
- // to constructors. In these cases, the references to classes aren't wanted
HashSet ignoreNodes = new HashSet<>();
- for (Tree node : nodes.keySet())
+ for (Tree node : nodes.keySet()) {
if (node instanceof NewClassTree) {
NewClassTree newClassTree = (NewClassTree) node;
if (newClassTree.getClassBody() == null) {
@@ -213,6 +314,7 @@ void resolveNodes() {
ignoreNodes.add(newClassTree.getIdentifier());
}
}
+ }
for (Map.Entry entry : nodes.entrySet()) {
Tree node = entry.getKey();
@@ -238,9 +340,6 @@ void resolveNodes() {
}
}
- // =======================================
- // Overridden methods from TreePathScanner
- // =======================================
@Override
public Void scan(Tree tree, Void unused) {
if (tree != null) {
@@ -250,25 +349,10 @@ public Void scan(Tree tree, Void unused) {
return super.scan(tree, unused);
}
- @Override
- public Void visitPackage(PackageTree node, Void unused) {
- // Stop traversal at the package declaration. JDK 17+ TreePathScanner
- // recurses into the package name's identifiers and would emit a
- // self-reference for `package X.Y;`; JDK 11 does not. Skipping the
- // whole package subtree keeps semanticdb output stable across JDKs and
- // matches the long-standing JDK 8/11 behavior of not emitting a
- // reference for the package declaration itself.
- return null;
- }
-
private boolean isAnonymous(Element sym) {
return sym.getSimpleName().length() == 0;
}
- public static B bar(A paramA, B paramB) {
- return paramB;
- }
-
private void resolveClassTree(ClassTree node, TreePath treePath) {
Element sym = trees.getElement(treePath);
if (sym != null && sym.getSimpleName().length() > 0) {
@@ -276,7 +360,7 @@ private void resolveClassTree(ClassTree node, TreePath treePath) {
sym,
node,
sym.getSimpleName(),
- Role.DEFINITION,
+ ScipRole.DEFINITION,
CompilerRange.FROM_POINT_WITH_TEXT_SEARCH);
}
}
@@ -285,7 +369,7 @@ private void resolveTypeParameterTree(TypeParameterTree node, TreePath treePath)
Element sym = trees.getElement(treePath);
if (sym != null && sym.getSimpleName().length() > 0) {
emitSymbolOccurrence(
- sym, node, sym.getSimpleName(), Role.DEFINITION, CompilerRange.FROM_POINT_TO_SYMBOL_NAME);
+ sym, node, sym.getSimpleName(), ScipRole.DEFINITION, CompilerRange.FROM_POINT_TO_SYMBOL_NAME);
}
}
@@ -299,7 +383,7 @@ private void resolveMethodTree(MethodTree node, TreePath treePath) {
else name = sym.getSimpleName();
emitSymbolOccurrence(
- sym, node, name, Role.DEFINITION, CompilerRange.FROM_POINT_WITH_TEXT_SEARCH);
+ sym, node, name, ScipRole.DEFINITION, CompilerRange.FROM_POINT_WITH_TEXT_SEARCH);
}
}
}
@@ -307,17 +391,17 @@ private void resolveMethodTree(MethodTree node, TreePath treePath) {
private void resolveVariableTree(VariableTree node, TreePath treePath) {
Element sym = trees.getElement(treePath);
if (sym != null) {
- Optional range =
+ Optional range =
emitSymbolOccurrence(
sym,
node,
sym.getSimpleName(),
- Role.DEFINITION,
+ ScipRole.DEFINITION,
CompilerRange.FROM_POINT_WITH_TEXT_SEARCH);
if (sym.getKind() == ElementKind.ENUM_CONSTANT) {
TreePath typeTreePath = nodes.get(node.getInitializer());
Element typeSym = trees.getElement(typeTreePath);
- if (typeSym != null) emitSymbolOccurrence(typeSym, range, Role.REFERENCE, Optional.empty());
+ if (typeSym != null) emitOccurrence(typeSym, range, ScipRole.REFERENCE, Optional.empty());
}
}
}
@@ -329,13 +413,12 @@ private void resolveIdentifierTree(IdentifierTree node, TreePath treePath) {
if (sym != null) {
boolean isThis = nodeName.toString().equals("this");
boolean isSuper = !isThis && nodeName.toString().equals("super");
- // exclude `this.` references but include `this(` and `super(` references
if (((sym.getKind() == ElementKind.CONSTRUCTOR) == isThis) || (isSuper)) {
TreePath parentPath = treePath.getParentPath();
Element parentSym = trees.getElement(parentPath);
if (parentSym == null || parentSym.getKind() != null) {
emitSymbolOccurrence(
- sym, node, sym.getSimpleName(), Role.REFERENCE, CompilerRange.FROM_START_TO_END);
+ sym, node, sym.getSimpleName(), ScipRole.REFERENCE, CompilerRange.FROM_START_TO_END);
}
}
}
@@ -346,7 +429,7 @@ private void resolveMemberReferenceTree(MemberReferenceTree node, TreePath treeP
Element sym = trees.getElement(treePath);
if (sym != null) {
emitSymbolOccurrence(
- sym, node, sym.getSimpleName(), Role.REFERENCE, CompilerRange.FROM_END_TO_SYMBOL_NAME);
+ sym, node, sym.getSimpleName(), ScipRole.REFERENCE, CompilerRange.FROM_END_TO_SYMBOL_NAME);
}
}
@@ -354,38 +437,33 @@ private void resolveMemberSelectTree(MemberSelectTree node, TreePath treePath) {
Element sym = trees.getElement(treePath);
if (sym != null) {
emitSymbolOccurrence(
- sym, node, sym.getSimpleName(), Role.REFERENCE, CompilerRange.FROM_END_TO_SYMBOL_NAME);
+ sym, node, sym.getSimpleName(), ScipRole.REFERENCE, CompilerRange.FROM_END_TO_SYMBOL_NAME);
}
}
private void resolveNewClassTree(NewClassTree node, TreePath treePath) {
- // ignore anonymous classes - otherwise there will be a local reference to itself
if (node.getIdentifier() != null && node.getClassBody() == null) {
Element sym = trees.getElement(treePath);
if (sym != null) {
TreePath parentPath = treePath.getParentPath();
Element parentSym = trees.getElement(parentPath);
-
if (parentSym == null || parentSym.getKind() != ElementKind.ENUM_CONSTANT) {
TreePath identifierTreePath = nodes.get(node.getIdentifier());
Element identifierSym = trees.getElement(identifierTreePath);
- // Simplest case, e.g. `new String()`
if (identifierSym != null) {
emitSymbolOccurrence(
sym,
node,
identifierSym.getSimpleName(),
- Role.REFERENCE,
+ ScipRole.REFERENCE,
CompilerRange.FROM_TEXT_SEARCH);
- }
- // More complex case, where the type is annotated: `new @TypeParameters String()`
- else if (node.getIdentifier().getKind() == Tree.Kind.ANNOTATED_TYPE) {
+ } else if (node.getIdentifier().getKind() == Tree.Kind.ANNOTATED_TYPE) {
AnnotatedTypeTree annotatedTypeTree = (AnnotatedTypeTree) node.getIdentifier();
if (annotatedTypeTree.getUnderlyingType() != null
&& annotatedTypeTree.getUnderlyingType().getKind() == Tree.Kind.IDENTIFIER) {
IdentifierTree ident = (IdentifierTree) annotatedTypeTree.getUnderlyingType();
emitSymbolOccurrence(
- sym, ident, ident.getName(), Role.REFERENCE, CompilerRange.FROM_TEXT_SEARCH);
+ sym, ident, ident.getName(), ScipRole.REFERENCE, CompilerRange.FROM_TEXT_SEARCH);
}
}
}
@@ -394,19 +472,14 @@ else if (node.getIdentifier().getKind() == Tree.Kind.ANNOTATED_TYPE) {
}
// =================================================
- // Utilities to generate SemanticDB data structures.
+ // Symbol / range helpers used by the SCIP emission path.
// =================================================
- private Semanticdb.Signature semanticdbSignature(Element sym) {
-
- return new SemanticdbSignatures(globals, locals, types).generateSignature(sym);
- }
-
private String semanticdbSymbol(Element sym) {
return globals.semanticdbSymbol(sym, locals);
}
- private Optional semanticdbRange(
+ private Optional scipRangeOf(
Tree tree, CompilerRange kind, Element sym, String name) {
if (sym == null) return Optional.empty();
@@ -425,97 +498,59 @@ private Optional semanticdbRange(
}
} else if (kind.isFromPoint()) {
if (start != Diagnostic.NOPOS) {
- // text may not exist or may be out of bounds (e.g. generated source like Lombok)
int testEnd = start + name.length();
- if (source.length() > testEnd && source.substring(start, testEnd).equals(name))
+ if (source.length() > testEnd && source.substring(start, testEnd).equals(name)) {
end = testEnd;
+ }
}
} else if (kind.isFromEndPoint()) {
if (end != Diagnostic.NOPOS) {
- // text may not exist or may be out of bounds (e.g. generated source like Lombok)
int testStart = end - name.length();
if (testStart >= 0
&& source.length() > end
- && source.substring(testStart, end).equals(name)) start = testStart;
+ && source.substring(testStart, end).equals(name)) {
+ start = testStart;
+ }
}
}
}
if (start != Diagnostic.NOPOS && end != Diagnostic.NOPOS && end > start) {
LineMap lineMap = compUnitTree.getLineMap();
- Semanticdb.Range range =
- Semanticdb.Range.newBuilder()
- .setStartLine((int) lineMap.getLineNumber(start) - 1)
- .setStartCharacter((int) lineMap.getColumnNumber(start) - 1)
- .setEndLine((int) lineMap.getLineNumber(end) - 1)
- .setEndCharacter((int) lineMap.getColumnNumber(end) - 1)
- .build();
+ ScipRange range =
+ new ScipRange(
+ (int) lineMap.getLineNumber(start) - 1,
+ (int) lineMap.getColumnNumber(start) - 1,
+ (int) lineMap.getLineNumber(end) - 1,
+ (int) lineMap.getColumnNumber(end) - 1);
range = correctForTabs(range, lineMap, start);
-
return Optional.of(range);
}
return Optional.empty();
}
- private Semanticdb.Range correctForTabs(Semanticdb.Range range, LineMap lineMap, int start) {
+ private ScipRange correctForTabs(ScipRange range, LineMap lineMap, int start) {
int startLinePos = (int) lineMap.getPosition(lineMap.getLineNumber(start), 0);
-
- // javac replaces every tab with 8 spaces in the linemap. As this is potentially inconsistent
- // with the source file itself, we adjust for that here if the line is actually indented with
- // tabs.
- // As for every tab there are 8 spaces, we remove 7 spaces for every tab to get the correct
- // char offset (note: different to _column_ offset your editor shows)
if (this.source.charAt(startLinePos) == '\t') {
int count = 1;
while (this.source.charAt(++startLinePos) == '\t') count++;
range =
- range
- .toBuilder()
- .setStartCharacter(range.getStartCharacter() - (count * 7))
- .setEndCharacter(range.getEndCharacter() - (count * 7))
- .build();
+ range.withCharacters(
+ range.startCharacter - (count * 7), range.endCharacter - (count * 7));
}
-
return range;
}
- private Optional semanticdbOccurrence(
- Element sym,
- Optional range,
- Role role,
- Optional enclosingRange) {
- if (range.isPresent()) {
- String ssym = semanticdbSymbol(sym);
- if (!ssym.equals(SemanticdbSymbols.NONE)) {
- Semanticdb.SymbolOccurrence occ = symbolOccurrence(ssym, range.get(), role, enclosingRange);
- return Optional.of(occ);
- } else {
- return Optional.empty();
- }
- } else {
- return Optional.empty();
- }
- }
-
- /**
- * Computes the enclosing range for the given tree node. Returns the range of the nearest
- * non-trivial enclosing AST node. For definition occurrences, this includes the entire definition
- * including documentation. For reference occurrences, this includes the parent expression bounds.
- */
- private Optional computeEnclosingRange(Tree tree) {
+ private Optional computeEnclosingRange(Tree tree) {
if (tree == null) return Optional.empty();
-
TreePath path = nodes.get(tree);
if (path == null) return Optional.empty();
- // For method, class, and variable definitions, use the tree itself as the enclosing range
- // since we're processing the definition node
Tree enclosingTree = tree;
if (!(tree instanceof MethodTree
|| tree instanceof ClassTree
|| tree instanceof VariableTree)) {
- // For non-definition nodes (like references), use the parent
TreePath parentPath = path.getParentPath();
if (parentPath == null) return Optional.empty();
enclosingTree = parentPath.getLeaf();
@@ -528,58 +563,26 @@ private Optional computeEnclosingRange(Tree tree) {
if (start != Diagnostic.NOPOS && end != Diagnostic.NOPOS && end > start) {
LineMap lineMap = compUnitTree.getLineMap();
- Semanticdb.Range range =
- Semanticdb.Range.newBuilder()
- .setStartLine((int) lineMap.getLineNumber(start) - 1)
- .setStartCharacter((int) lineMap.getColumnNumber(start) - 1)
- .setEndLine((int) lineMap.getLineNumber(end) - 1)
- .setEndCharacter((int) lineMap.getColumnNumber(end) - 1)
- .build();
-
+ ScipRange range =
+ new ScipRange(
+ (int) lineMap.getLineNumber(start) - 1,
+ (int) lineMap.getColumnNumber(start) - 1,
+ (int) lineMap.getLineNumber(end) - 1,
+ (int) lineMap.getColumnNumber(end) - 1);
range = correctForTabs(range, lineMap, start);
-
return Optional.of(range);
}
-
return Optional.empty();
}
- private String semanticdbText() {
- if (source != null) return source;
+ private static String sourceText(CompilationUnitTree tree) {
try {
- source = compUnitTree.getSourceFile().getCharContent(true).toString();
+ return tree.getSourceFile().getCharContent(true).toString();
} catch (IOException e) {
- source = "";
- }
- return source;
- }
-
- private String semanticdbMd5() {
- try {
- return MD5.digest(compUnitTree.getSourceFile().getCharContent(true).toString());
- } catch (IOException | NoSuchAlgorithmException e) {
return "";
}
}
- private int semanticdbSymbolInfoProperties(Element sym) {
- int properties = 0;
- properties |=
- sym.getKind() == ElementKind.ENUM || sym.getKind() == ElementKind.ENUM_CONSTANT
- ? Property.ENUM_VALUE
- : 0;
- for (Modifier modifier : sym.getModifiers()) {
- if (modifier == Modifier.STATIC) properties |= Property.STATIC_VALUE;
- else if (modifier == Modifier.DEFAULT) properties |= Property.DEFAULT_VALUE;
- else if (modifier == Modifier.FINAL) properties |= Property.FINAL_VALUE;
- else if (modifier == Modifier.ABSTRACT) properties |= Property.ABSTRACT_VALUE;
- }
- // for default interface methods, Modifier.ABSTRACT is also set...
- if (((properties & Property.ABSTRACT_VALUE) > 0) && ((properties & Property.DEFAULT_VALUE) > 0))
- properties ^= Property.ABSTRACT_VALUE;
- return properties;
- }
-
private List semanticdbParentSymbols(TypeElement typeElement) {
ArrayList parentSymbols = new ArrayList<>();
Set parentElements = semanticdbParentTypeElements(typeElement, new HashSet<>());
@@ -599,14 +602,13 @@ private Set semanticdbParentTypeElements(
for (TypeMirror interfaceType : typeElement.getInterfaces()) {
semanticdbParentSymbol(interfaceType, result);
}
-
return result;
}
private void semanticdbParentSymbol(TypeMirror elementType, Set result) {
if (!(elementType instanceof NoType)) {
Element superElement = types.asElement(elementType);
- if (superElement != null && superElement instanceof TypeElement) {
+ if (superElement instanceof TypeElement) {
result.add((TypeElement) superElement);
semanticdbParentTypeElements((TypeElement) superElement, result);
}
@@ -617,20 +619,16 @@ private Set semanticdbOverrides(
ExecutableElement sym, Element enclosingElement, HashSet overriddenSymbols) {
if (enclosingElement instanceof TypeElement) {
List extends TypeMirror> superTypes = types.directSupertypes(enclosingElement.asType());
- // iterate through all super types
for (TypeMirror superType : superTypes) {
if (superType instanceof DeclaredType) {
Element superElement = ((DeclaredType) superType).asElement();
- // find all elements of super class
if (superElement instanceof TypeElement) {
boolean methodFound = false;
List extends Element> enclosedElements =
((TypeElement) superElement).getEnclosedElements();
for (Element enclosedElement : enclosedElements) {
- // check the element is a method
if (enclosedElement instanceof ExecutableElement) {
ExecutableElement enclosedExecutableElement = (ExecutableElement) enclosedElement;
- // check the method overrides the original method
if (elements.overrides(
sym, enclosedExecutableElement, (TypeElement) sym.getEnclosingElement())) {
String symbol = semanticdbSymbol(enclosedExecutableElement);
@@ -650,16 +648,7 @@ private Set semanticdbOverrides(
return overriddenSymbols;
}
- private Semanticdb.Access semanticdbAccess(Element sym) {
- for (Modifier modifier : sym.getModifiers()) {
- if (modifier == Modifier.PRIVATE) return privateAccess();
- if (modifier == Modifier.PUBLIC) return publicAccess();
- if (modifier == Modifier.PROTECTED) return protectedAccess();
- }
- return privateWithinAccess(semanticdbSymbol(sym.getEnclosingElement()));
- }
-
- private static String semanticdbUri(
+ private static String sourceRelativePath(
CompilationUnitTree compUnitTree, SemanticdbJavacOptions options) {
Path absolutePath =
SemanticdbTaskListener.absolutePathFromUri(options, compUnitTree.getSourceFile());
@@ -677,24 +666,12 @@ private static String semanticdbUri(
return out.toString();
}
- private Semanticdb.Documentation semanticdbDocumentation(Tree tree) {
+ private String semanticdbDocumentation(Tree tree) {
try {
TreePath treePath = nodes.get(tree);
String doc = trees.getDocComment(treePath);
- if (doc == null) return null;
-
- return Semanticdb.Documentation.newBuilder()
- .setFormat(Semanticdb.Documentation.Format.JAVADOC)
- .setMessage(doc)
- .build();
+ return doc;
} catch (NullPointerException e) {
- // Can happen in `getDocComment()`
- // Caused by: java.lang.NullPointerException
- // at com.sun.tools.javac.model.JavacElements.cast(JavacElements.java:605)
- // at com.sun.tools.javac.model.JavacElements.getTreeAndTopLevel(JavacElements.java:543)
- // at com.sun.tools.javac.model.JavacElements.getDocComment(JavacElements.java:321)
- // at
- // com.sourcegraph.semanticdb_javac.SemanticdbVisitor.semanticdbDocumentation(SemanticdbVisitor.java:233)
return null;
}
}
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbJavacOptions.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbJavacOptions.java
index 672813a47..e42c9fa43 100644
--- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbJavacOptions.java
+++ b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbJavacOptions.java
@@ -18,12 +18,13 @@
/** Settings that can be configured alongside the -Xplugin compiler option. */
public class SemanticdbJavacOptions {
- /** The directory to place META-INF and its .semanticdb files */
+ /** The directory to place META-INF and its SCIP shard files */
public Path targetroot;
public Path sourceroot;
public boolean includeText = false;
public boolean verboseEnabled = false;
+
public final ArrayList errors;
public boolean alreadyReportedErrors = false;
public UriScheme uriScheme = UriScheme.DEFAULT;
@@ -97,6 +98,9 @@ public static SemanticdbJavacOptions parse(String[] args, JavacTask task) {
result.verboseEnabled = true;
} else if (arg.equals("-verbose:off")) {
result.verboseEnabled = false;
+ } else if (arg.equals("-emit-scip:on") || arg.equals("-emit-scip:off")) {
+ // Deprecated no-op: SCIP shard emission is now unconditional. The flag is still parsed so
+ // older callers / cached compiler options keep working without errors.
} else if (arg.startsWith("-randomtimestamp")) {
} else {
result.errors.add(String.format("unknown flag '%s'\n", arg));
diff --git a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbSignatures.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbSignatures.java
deleted file mode 100644
index 6e4fedf0e..000000000
--- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbSignatures.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.sourcegraph.semanticdb_javac;
-
-import com.sourcegraph.semanticdb_javac.Semanticdb.*;
-
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.element.TypeParameterElement;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Types;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.sourcegraph.semanticdb_javac.SemanticdbBuilders.*;
-import static com.sourcegraph.semanticdb_javac.SemanticdbTypeVisitor.UNRESOLVED_TYPE_REF;
-
-public final class SemanticdbSignatures {
- private final GlobalSymbolsCache cache;
- private final LocalSymbolsCache locals;
- private final Types types;
-
- public SemanticdbSignatures(GlobalSymbolsCache cache, LocalSymbolsCache locals, Types types) {
- this.cache = cache;
- this.locals = locals;
- this.types = types;
- }
-
- public Signature generateSignature(Element sym) {
- if (sym instanceof TypeElement) {
- return generateClassSignature((TypeElement) sym);
- } else if (sym instanceof ExecutableElement) {
- return generateMethodSignature((ExecutableElement) sym);
- } else if (sym instanceof VariableElement) {
- return generateFieldSignature((VariableElement) sym);
- } else if (sym instanceof TypeParameterElement) {
- return generateTypeSignature((TypeParameterElement) sym);
- }
- return null;
- }
-
- private Signature generateClassSignature(TypeElement sym) {
- ClassSignature.Builder builder = ClassSignature.newBuilder();
-
- builder.setTypeParameters(generateScope(sym.getTypeParameters()));
-
- for (TypeMirror superType : types.directSupertypes(sym.asType())) {
- Semanticdb.Type semanticdbType = generateType(superType);
- if (semanticdbType == null) {
- semanticdbType = UNRESOLVED_TYPE_REF;
- }
- builder.addParents(semanticdbType);
- }
-
- builder.setDeclarations(generateScope(sym.getEnclosedElements()));
-
- return signature(builder);
- }
-
- private Signature generateMethodSignature(ExecutableElement sym) {
- MethodSignature.Builder builder = MethodSignature.newBuilder();
-
- builder.setTypeParameters(generateScope(sym.getTypeParameters()));
-
- builder.addParameterLists(generateScope(sym.getParameters()));
-
- Semanticdb.Type returnType = generateType(sym.getReturnType());
- if (returnType != null) {
- builder.setReturnType(returnType);
- }
-
- List thrownTypes =
- sym.getThrownTypes().stream().map(this::generateType).collect(Collectors.toList());
- builder.addAllThrows(thrownTypes);
-
- return signature(builder);
- }
-
- private Signature generateFieldSignature(VariableElement sym) {
- Semanticdb.Type generateType = generateType(sym.asType());
- if (generateType == null) {
- generateType = UNRESOLVED_TYPE_REF;
- }
- return signature(ValueSignature.newBuilder().setTpe(generateType));
- }
-
- private Signature generateTypeSignature(TypeParameterElement sym) {
- TypeSignature.Builder builder = TypeSignature.newBuilder();
-
- if (sym instanceof TypeElement) {
- builder.setTypeParameters(generateScope(((TypeElement) sym).getTypeParameters()));
- }
-
- TypeMirror varType = sym.asType();
- if (varType instanceof TypeVariable) {
- Semanticdb.Type upperBound = generateType(((TypeVariable) varType).getUpperBound());
- if (upperBound != null) builder.setUpperBound(upperBound);
- else builder.setUpperBound(UNRESOLVED_TYPE_REF);
- } else builder.setUpperBound(UNRESOLVED_TYPE_REF);
-
- return signature(builder);
- }
-
- private Scope generateScope(List extends Element> elements) {
- Scope.Builder scope = Scope.newBuilder();
- for (Element typeVar : elements) {
- scope.addSymlinks(cache.semanticdbSymbol(typeVar, locals));
- }
- return scope.build();
- }
-
- private Semanticdb.Type generateType(TypeMirror mirror) {
- return new SemanticdbTypeVisitor(cache, locals, types).semanticdbType(mirror);
- }
-}
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 7c5238f65..c7ce170ef 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
@@ -8,18 +8,18 @@
import javax.lang.model.util.Types;
import javax.tools.JavaFileObject;
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.stream.Collectors;
/**
- * Callback hook that generates SemanticDB when the compiler has completed typechecking a Java
- * source file.
+ * Callback hook that drives {@link ScipVisitor} after javac finishes typechecking a Java source
+ * file. The visitor builds a self-contained {@code *.scip} shard which is written (or merged)
+ * under {@code META-INF/scip/...}.
*/
public final class SemanticdbTaskListener implements TaskListener {
private final SemanticdbJavacOptions options;
@@ -46,15 +46,14 @@ public SemanticdbTaskListener(
@Override
public void started(TaskEvent e) {
- // Upon first encounter with a file (before any other tasks are run)
- // we remove the semanticdb file for this source file to ensure
- // stale data doesn't cause problems
+ // Upon first encounter with a file (before any other tasks are run) we remove any prior SCIP
+ // shard for this source file to avoid accumulating stale occurrences across builds.
if (e.getKind() == TaskEvent.Kind.ENTER) {
inferBazelSourceroot(e.getSourceFile());
- Result semanticdbPath = semanticdbOutputPath(options, e);
- if (semanticdbPath.isOk()) {
+ Result shardPath = scipShardOutputPath(options, e);
+ if (shardPath != null && shardPath.isOk()) {
try {
- Files.deleteIfExists(semanticdbPath.getOrThrow());
+ Files.deleteIfExists(shardPath.getOrThrow());
} catch (IOException ex) {
this.reportException(ex, e);
}
@@ -78,12 +77,8 @@ public void finished(TaskEvent e) {
try {
onFinishedAnalyze(e);
} catch (Throwable ex) {
- // Catch exceptions because we don't want to stop the compilation even if this
- // plugin has a
+ // Catch exceptions because we don't want to stop the compilation even if this plugin has a
// bug. We report the full stack trace because it's helpful for bug reports.
- // Exceptions
- // should only happen in *exceptional* situations and they should be reported
- // upstream.
Throwable throwable = ex;
if (e.getSourceFile() != null) {
throwable =
@@ -94,10 +89,8 @@ public void finished(TaskEvent e) {
}
}
- // Uses reporter.error with the full stack trace of the exception instead of
- // reporter.exception
- // because reporter.exception doesn't seem to print any meaningful information
- // about the
+ // Uses reporter.error with the full stack trace of the exception instead of reporter.exception
+ // because reporter.exception doesn't seem to print any meaningful information about the
// exception, it just prints the location with an empty message.
private void reportException(Throwable exception, TaskEvent e) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -108,101 +101,21 @@ private void reportException(Throwable exception, TaskEvent e) {
}
private void onFinishedAnalyze(TaskEvent e) {
- Result path = semanticdbOutputPath(options, e);
- if (path != null) {
- if (path.isOk()) {
- Semanticdb.TextDocument textDocument =
- new SemanticdbVisitor(globals, e.getCompilationUnit(), options, types, trees, elements)
- .buildTextDocument(e.getCompilationUnit());
- Path output = path.getOrThrow();
- if (Files.exists(output)) appendSemanticdb(e, output, textDocument);
- else writeSemanticdb(e, output, textDocument);
- } else {
- reporter.error(path.getErrorOrThrow(), e);
- }
- }
- }
-
- private void writeSemanticdb(TaskEvent event, Path output, Semanticdb.TextDocument textDocument) {
- try {
- byte[] bytes =
- Semanticdb.TextDocuments.newBuilder().addDocuments(textDocument).build().toByteArray();
- Files.createDirectories(output.getParent());
- Files.write(output, bytes);
- } catch (IOException e) {
- this.reportException(e, event);
- }
- }
-
- private void appendSemanticdb(
- TaskEvent event, Path output, Semanticdb.TextDocument textDocument) {
- /*
- * If there already is a semanticdb file at the given path,
- * we do the following:
- * - Read a documents collection
- * - Try to find the document with the matching relative path (matching the incoming textDocument)
- * - Then, depending on whether a matching document already exists in the collection:
- * - if YES, mutate it in place to only add entries from the incoming document
- * - if NO, simply add the incoming text document to the collection
- * - Write the collection back to disk
- * */
- Semanticdb.TextDocument document = null;
- int documentIndex = -1;
- Semanticdb.TextDocuments documents = null;
-
- try (InputStream is = Files.newInputStream(output.toFile().toPath())) {
- documents = Semanticdb.TextDocuments.parseFrom(is);
-
- for (int i = 0; i < documents.getDocumentsCount(); i++) {
- Semanticdb.TextDocument candidate = documents.getDocuments(i);
- if (document == null && candidate.getUri().equals(textDocument.getUri())) {
- document = candidate;
- documentIndex = i;
- }
- }
-
- } catch (IOException e) {
- this.reportException(e, event);
+ Result path = scipShardOutputPath(options, e);
+ if (path == null) return;
+ if (!path.isOk()) {
+ reporter.error(path.getErrorOrThrow(), e);
return;
}
- if (document != null) {
- // If there is a previous semanticdb document at this path, we need
- // to deduplicate symbols and occurrences and mutate the document in place
- Set symbols = new HashSet<>(textDocument.getSymbolsList());
- Set occurrences =
- new HashSet<>(textDocument.getOccurrencesList());
- Set synthetics = new HashSet<>(textDocument.getSyntheticsList());
-
- symbols.addAll(document.getSymbolsList());
- occurrences.addAll(document.getOccurrencesList());
- synthetics.addAll(document.getSyntheticsList());
-
- documents
- .toBuilder()
- .addDocuments(
- documentIndex,
- document
- .toBuilder()
- .clearOccurrences()
- .addAllOccurrences(occurrences)
- .clearSymbols()
- .addAllSymbols(symbols)
- .clearSynthetics()
- .addAllSynthetics(synthetics));
-
- } else {
- // If no prior document was found, we can just add the incoming one to the collection
- documents = documents.toBuilder().addDocuments(textDocument).build();
- }
-
- byte[] bytes = documents.toByteArray();
-
+ Path shardPath = path.getOrThrow();
try {
- Files.createDirectories(output.getParent());
- Files.write(output, bytes);
- } catch (IOException e) {
- this.reportException(e, event);
+ com.sourcegraph.Scip.Index shard =
+ new ScipVisitor(globals, e.getCompilationUnit(), options, types, trees, elements)
+ .buildShard(e.getCompilationUnit());
+ ScipShardWriter.writeOrMerge(shardPath, shard);
+ } catch (IOException ex) {
+ this.reportException(ex, e);
}
}
@@ -219,16 +132,11 @@ public static Path absolutePathFromUri(SemanticdbJavacOptions options, JavaFileO
}
} else if (options.uriScheme == UriScheme.BAZEL) {
String toString = file.toString().replace(":", "/");
- // This solution is hacky, and it would be very nice to use a dedicated API
- // instead.
- // The Bazel Java compiler constructs `SimpleFileObject/DirectoryFileObject`
- // with a
- // "user-friendly" name that points to the original source file and an
- // underlying/actual
- // file path in a temporary directory. We're constrained by having to use only
- // public APIs of
- // the Java compiler and `toString()` seems to be the only way to access the
- // user-friendly
+ // This solution is hacky, and it would be very nice to use a dedicated API instead.
+ // The Bazel Java compiler constructs `SimpleFileObject/DirectoryFileObject` with a
+ // "user-friendly" name that points to the original source file and an underlying/actual
+ // file path in a temporary directory. We're constrained by having to use only public APIs of
+ // the Java compiler and `toString()` seems to be the only way to access the user-friendly
// path.
String[] knownBazelToStringPatterns =
new String[] {"SimpleFileObject[", "DirectoryFileObject["};
@@ -255,19 +163,7 @@ private void inferBazelSourceroot(JavaFileObject file) {
}
Path absolutePath = absolutePathFromUri(options, file);
Path uriPath = Paths.get(file.toUri());
- // absolutePath is the "human-readable" original path, for example
- // /home/repo/com/example/Hello.java
- // uriPath is the sandbox/temporary file path, for example
- // /private/var/tmp/com/example/Hello.java
- //
- // We infer sourceroot by iterating the names of both files in reverse order
- // and stop at the first entry where the two paths are different. For the
- // example above, we compare "Hello.java", then "example", then "com", and
- // when we reach "repo" != "tmp" then we guess that "/home/repo" is the
- // sourceroot. This logic is brittle and it would be nice to use more
- // dedicated APIs, but Bazel actively makes an effort to sandbox
- // compilation and hide access to the original workspace, which is why we
- // resort to solutions like this.
+ // See comments in the previous implementation for the rationale of the inference loop below.
int relativePathDepth = 0;
int uriPathDepth = uriPath.getNameCount();
int absolutePathDepth = absolutePath.getNameCount();
@@ -285,41 +181,36 @@ private void inferBazelSourceroot(JavaFileObject file) {
.resolve(absolutePath.subpath(0, absolutePathDepth - relativePathDepth));
}
- private Result semanticdbOutputPath(SemanticdbJavacOptions options, TaskEvent e) {
+ private Result scipShardOutputPath(SemanticdbJavacOptions options, TaskEvent e) {
Path absolutePath = absolutePathFromUri(options, e.getSourceFile());
if (absolutePath.startsWith(options.sourceroot)) {
Path relativePath = options.sourceroot.relativize(absolutePath);
- String filename = relativePath.getFileName().toString() + ".semanticdb";
- Path semanticdbOutputPath =
+ String filename = relativePath.getFileName().toString() + ".scip";
+ Path scipOutputPath =
options
.targetroot
.resolve("META-INF")
- .resolve("semanticdb")
+ .resolve("scip")
.resolve(relativePath)
.resolveSibling(filename);
- return Result.ok(semanticdbOutputPath);
+ return Result.ok(scipOutputPath);
}
switch (options.noRelativePath) {
case INDEX_ANYWAY:
- // Come up with a unique relative path for this file even if it's not under the
- // sourceroot.
- // By indexing auto-generated files, we collect SymbolInformation for
- // auto-generated symbol,
- // which results in more useful hover tooltips in the editor.
- // In the future, we may want to additionally embed the full text contents of
- // these files
- // so that it's possible to browse generated files with precise code navigation.
+ // Come up with a unique relative path for this file even if it's not under the sourceroot.
+ // By indexing auto-generated files, we collect SymbolInformation for auto-generated
+ // symbols, which results in more useful hover tooltips in the editor.
String uniqueFilename =
- String.format("%d.%s.semanticdb", ++noRelativePathCounter, absolutePath.getFileName());
- Path semanticdbOutputPath =
+ String.format("%d.%s.scip", ++noRelativePathCounter, absolutePath.getFileName());
+ Path scipOutputPath =
options
.targetroot
.resolve("META-INF")
- .resolve("semanticdb")
+ .resolve("scip")
.resolve("no-relative-path")
.resolve(uniqueFilename);
- return Result.ok(semanticdbOutputPath);
+ return Result.ok(scipOutputPath);
case WARNING:
reporter.info(
String.format(
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
deleted file mode 100644
index f78b5abe6..000000000
--- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTrees.java
+++ /dev/null
@@ -1,258 +0,0 @@
-package com.sourcegraph.semanticdb_javac;
-
-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 java.util.HashMap;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.sourcegraph.semanticdb_javac.SemanticdbBuilders.*;
-import static com.sourcegraph.semanticdb_javac.SemanticdbTypeVisitor.ARRAY_SYMBOL;
-
-public class SemanticdbTrees {
- public SemanticdbTrees(
- GlobalSymbolsCache globals,
- LocalSymbolsCache locals,
- String semanticdbUri,
- Types types,
- Trees trees,
- HashMap nodes) {
- this.globals = globals;
- this.locals = locals;
- this.semanticdbUri = semanticdbUri;
- this.types = types;
- this.trees = trees;
- this.nodes = nodes;
- this.typeVisitor = new SemanticdbTypeVisitor(globals, locals, types);
- }
-
- private final GlobalSymbolsCache globals;
- private final LocalSymbolsCache locals;
- private final String semanticdbUri;
- 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)
- && !(node instanceof MethodTree)
- && !(node instanceof VariableTree)) return null;
-
- List annotations = new ArrayList<>();
-
- ModifiersTree mods;
- if (node instanceof ClassTree) {
- mods = ((ClassTree) node).getModifiers();
- } else if (node instanceof MethodTree) {
- mods = ((MethodTree) node).getModifiers();
- } else {
- mods = ((VariableTree) node).getModifiers();
- }
-
- for (AnnotationTree annotation : mods.getAnnotations()) {
- annotations.add(annotationBuilder(annotation));
- }
-
- return annotations;
- }
-
- 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
- // resolve symbols fully
- if (param instanceof AssignmentTree) {
- AssignmentTree assign = (AssignmentTree) param;
- ExpressionTree assignValue = assign.getExpression();
- TreePath variableTreePath = nodes.get(assign.getVariable());
- if (variableTreePath != null) {
- Element variableSym = trees.getElement(variableTreePath);
- String symbol = globals.semanticdbSymbol(variableSym, locals);
- params.add(tree(assignTree(tree(idTree(symbol)), annotationParameter(assignValue))));
- }
- } else {
- params.add(annotationParameter(param));
- }
- }
-
- TreePath annotationTreePath = nodes.get(annotation);
- Element annotationSym = trees.getElement(annotationTreePath);
-
- 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);
- Element expressionSym = trees.getElement(expressionTreePath);
- return tree(
- selectTree(
- tree(idTree(globals.semanticdbSymbol(expressionSym.getEnclosingElement(), locals))),
- idTree(globals.semanticdbSymbol(expressionSym, locals))));
- } else if (expr instanceof NewArrayTree) {
- NewArrayTree rhs = (NewArrayTree) expr;
- return tree(
- applyTree(
- tree(idTree(ARRAY_SYMBOL)),
- rhs.getInitializers().stream()
- .map(this::annotationParameter)
- .collect(Collectors.toList())));
- } else if (expr instanceof LiteralTree) {
- // Literals can either be a primitive or String
- Object value = ((LiteralTree) expr).getValue();
- final Semanticdb.Constant constant;
- // 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);
- else if (value instanceof Integer) constant = intConst((Integer) value);
- else if (value instanceof Long) constant = longConst((Long) value);
- else if (value instanceof Character) constant = charConst((Character) value);
- else if (value instanceof Float) constant = floatConst((Float) value);
- else if (value instanceof Double) constant = doubleConst((Double) value);
- else
- throw new IllegalStateException(
- semanticdbUri
- + ": annotation parameter rhs was of unexpected class type "
- + value.getClass()
- + "\n"
- + value);
- return tree(literalTree(constant));
- } else if (expr instanceof AnnotationTree) {
- return tree(annotationBuilder((AnnotationTree) expr));
- } else if (expr instanceof IdentifierTree) {
- TreePath expressionTreePath = nodes.get(expr);
- Element expressionSym = trees.getElement(expressionTreePath);
- return tree(idTree(globals.semanticdbSymbol(expressionSym, locals)));
- } else if (expr instanceof BinaryTree) {
- BinaryTree binExpr = (BinaryTree) expr;
- return tree(
- binopTree(
- 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())));
- } 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);
- }
- }
-
- 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 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/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTypeVisitor.java b/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTypeVisitor.java
deleted file mode 100644
index 0733dbbfd..000000000
--- a/semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbTypeVisitor.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.sourcegraph.semanticdb_javac;
-
-import javax.lang.model.element.Element;
-import javax.lang.model.util.SimpleTypeVisitor8;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.IntersectionType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.NoType;
-import javax.lang.model.util.Types;
-import java.util.ArrayList;
-
-import static com.sourcegraph.semanticdb_javac.SemanticdbBuilders.*;
-
-/** A TypeMirror tree visitor that constructs a recursive SemanticDB Type structure. */
-class SemanticdbTypeVisitor extends SimpleTypeVisitor8 {
- static final Semanticdb.Type UNRESOLVED_TYPE_REF = typeRef("unresolved_type#");
-
- static final String ARRAY_SYMBOL = "scala/Array#";
-
- private final GlobalSymbolsCache cache;
- private final LocalSymbolsCache locals;
- private final Types types;
-
- SemanticdbTypeVisitor(GlobalSymbolsCache cache, LocalSymbolsCache locals, Types types) {
- this.cache = cache;
- this.locals = locals;
- this.types = types;
- }
-
- public Semanticdb.Type semanticdbType(TypeMirror tpe) {
- Semanticdb.Type result = super.visit(tpe);
- return result == null ? UNRESOLVED_TYPE_REF : result;
- }
-
- @Override
- public Semanticdb.Type visitDeclared(DeclaredType t, Void unused) {
- boolean isExistential =
- t.getTypeArguments().stream().anyMatch((type) -> type instanceof WildcardType);
-
- ArrayList typeParams = new ArrayList<>();
- Semanticdb.Scope.Builder declarations = Semanticdb.Scope.newBuilder();
- for (TypeMirror type : t.getTypeArguments()) {
- typeParams.add(semanticdbType(type));
-
- if (type instanceof WildcardType) {
- Semanticdb.TypeSignature.Builder typeSig = Semanticdb.TypeSignature.newBuilder();
- WildcardType wildcardType = (WildcardType) type;
-
- // semanticdb spec asks for List() not None for type_parameters field
- typeSig.setTypeParameters(Semanticdb.Scope.newBuilder());
-
- if (wildcardType.getExtendsBound() != null) {
- typeSig.setUpperBound(super.visit(wildcardType.getExtendsBound()));
- } else if (wildcardType.getSuperBound() != null) {
- typeSig.setLowerBound(super.visit(wildcardType.getSuperBound()));
- }
-
- declarations.addHardlinks(
- Semanticdb.SymbolInformation.newBuilder()
- .setSymbol("local_wildcard")
- .setSignature(Semanticdb.Signature.newBuilder().setTypeSignature(typeSig)));
- } else {
- Element element = types.asElement(type);
- declarations.addSymlinks(cache.semanticdbSymbol(element, locals));
- }
- }
-
- if (!isExistential) {
- return typeRef(cache.semanticdbSymbol(t.asElement(), locals), typeParams);
- } else {
- return existentialType(
- typeRef(cache.semanticdbSymbol(t.asElement(), locals), typeParams), declarations.build());
- }
- }
-
- @Override
- public Semanticdb.Type visitArray(ArrayType t, Void unused) {
- ArrayList types = new ArrayList();
- types.add(semanticdbType(t.getComponentType()));
- return typeRef(ARRAY_SYMBOL, types);
- }
-
- @Override
- public Semanticdb.Type visitPrimitive(PrimitiveType t, Void unused) {
- return typeRef(primitiveSymbol(t.getKind()));
- }
-
- @Override
- public Semanticdb.Type visitTypeVariable(TypeVariable t, Void unused) {
- return typeRef(cache.semanticdbSymbol(t.asElement(), locals));
- }
-
- @Override
- public Semanticdb.Type visitIntersection(IntersectionType t, Void unused) {
- ArrayList types = new ArrayList<>();
- for (TypeMirror type : t.getBounds()) {
- types.add(super.visit(type));
- }
-
- return intersectionType(types);
- }
-
- @Override
- public Semanticdb.Type visitWildcard(WildcardType t, Void unused) {
- // https://github.com/scalameta/scalameta/issues/1703
- // https://sourcegraph.com/github.com/scalameta/scalameta/-/blob/semanticdb/metacp/src/main/scala/scala/meta/internal/javacp/Javacp.scala#L452:19
- return typeRef("local_wildcard");
- }
-
- @Override
- public Semanticdb.Type visitNoType(NoType t, Void unused) {
- return typeRef(primitiveSymbol(t.getKind()));
- }
-
- public String primitiveSymbol(TypeKind kind) {
- switch (kind) {
- case BOOLEAN:
- return "scala/Boolean#";
- case BYTE:
- return "scala/Byte#";
- case SHORT:
- return "scala/Short#";
- case INT:
- return "scala/Int#";
- case LONG:
- return "scala/Long#";
- case CHAR:
- return "scala/Char#";
- case FLOAT:
- return "scala/Float#";
- case DOUBLE:
- return "scala/Double#";
- case VOID:
- return "scala/Unit#";
- default:
- throw new IllegalArgumentException("got " + kind.name());
- }
- }
-}
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ClassConsumer.java b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ClassConsumer.java
index 299966fdd..b50629be4 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ClassConsumer.java
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ClassConsumer.java
@@ -1,28 +1,28 @@
package snapshots;
-//⌄ enclosing_range_start semanticdb maven . . snapshots/ClassConsumer#
+//⌄ enclosing_range_start scip-java maven . . snapshots/ClassConsumer#
public class ClassConsumer {
-// ^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/ClassConsumer#
+// ^^^^^^^^^^^^^ definition scip-java maven . . snapshots/ClassConsumer#
// display_name ClassConsumer
// signature_documentation java public class ClassConsumer
// kind Class
-// ^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/ClassConsumer#``().
+// ^^^^^^^^^^^^^ definition scip-java maven . . snapshots/ClassConsumer#``().
// display_name
// signature_documentation java public ClassConsumer()
// kind Constructor
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/ClassConsumer#run().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/ClassConsumer#run().
public static void run() {
-// ^^^ definition semanticdb maven . . snapshots/ClassConsumer#run().
+// ^^^ definition scip-java maven . . snapshots/ClassConsumer#run().
// display_name run
// signature_documentation java public static void run()
// kind StaticMethod
System.out.println(new Class().getAsdf());
-// ^^^^^^ reference semanticdb maven jdk 11 java/lang/System#
-// ^^^ reference semanticdb maven jdk 11 java/lang/System#out.
-// ^^^^^^^ reference semanticdb maven jdk 11 java/io/PrintStream#println(+9).
-// ^^^^^ reference semanticdb maven . . snapshots/Class#``(+1).
-// ^^^^^^^ reference semanticdb maven . . snapshots/Class#getAsdf().
+// ^^^^^^ reference scip-java maven jdk 11 java/lang/System#
+// ^^^ reference scip-java maven jdk 11 java/lang/System#out.
+// ^^^^^^^ reference scip-java maven jdk 11 java/io/PrintStream#println(+9).
+// ^^^^^ reference scip-java maven . . snapshots/Class#``(+1).
+// ^^^^^^^ reference scip-java maven . . snapshots/Class#getAsdf().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/ClassConsumer#run().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/ClassConsumer#run().
}
-//⌃ enclosing_range_end semanticdb maven . . snapshots/ClassConsumer#
+//⌃ enclosing_range_end scip-java maven . . snapshots/ClassConsumer#
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/CompanionConsumer.java b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/CompanionConsumer.java
index 6708477bb..962c6bbce 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/CompanionConsumer.java
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/CompanionConsumer.java
@@ -1,25 +1,25 @@
package snapshots;
-//⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionConsumer#
+//⌄ enclosing_range_start scip-java maven . . snapshots/CompanionConsumer#
public class CompanionConsumer {
-// ^^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/CompanionConsumer#
+// ^^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/CompanionConsumer#
// display_name CompanionConsumer
// signature_documentation java public class CompanionConsumer
// kind Class
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionConsumer#``().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/CompanionConsumer#``().
CompanionConsumer() {
-// ^^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/CompanionConsumer#``().
+// ^^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/CompanionConsumer#``().
// display_name
// signature_documentation java CompanionConsumer()
// kind Constructor
CompanionOwner.Companion.create();
-// ^^^^^^^^^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#
-// ^^^^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#Companion.
-// ^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#Companion#create().
+// ^^^^^^^^^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#
+// ^^^^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#Companion.
+// ^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#Companion#create().
new CompanionOwner().create();
-// ^^^^^^^^^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#``().
-// ^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#create().
+// ^^^^^^^^^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#``().
+// ^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#create().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/CompanionConsumer#``().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/CompanionConsumer#``().
}
-//⌃ enclosing_range_end semanticdb maven . . snapshots/CompanionConsumer#
+//⌃ enclosing_range_end scip-java maven . . snapshots/CompanionConsumer#
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinClass.java b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinClass.java
index 82ea72ed4..77785c36a 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinClass.java
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinClass.java
@@ -1,45 +1,45 @@
package snapshots;
-//⌄ enclosing_range_start semanticdb maven . . snapshots/KotlinClass#
+//⌄ enclosing_range_start scip-java maven . . snapshots/KotlinClass#
public class KotlinClass {
-// ^^^^^^^^^^^ definition semanticdb maven . . snapshots/KotlinClass#
+// ^^^^^^^^^^^ definition scip-java maven . . snapshots/KotlinClass#
// display_name KotlinClass
// signature_documentation java public class KotlinClass
// kind Class
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/KotlinClass#``().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/KotlinClass#``().
KotlinClass() throws Class {
-// ^^^^^^^^^^^ definition semanticdb maven . . snapshots/KotlinClass#``().
+// ^^^^^^^^^^^ definition scip-java maven . . snapshots/KotlinClass#``().
// display_name
// signature_documentation java KotlinClass() throws Class
// kind Constructor
-// ^^^^^ reference semanticdb maven . . snapshots/Class#
+// ^^^^^ reference scip-java maven . . snapshots/Class#
throw new Class();
-// ^^^^^ reference semanticdb maven . . snapshots/Class#``(+1).
+// ^^^^^ reference scip-java maven . . snapshots/Class#``(+1).
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/KotlinClass#``().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/KotlinClass#``().
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/KotlinClass#test().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/KotlinClass#test().
void test() throws Class {
-// ^^^^ definition semanticdb maven . . snapshots/KotlinClass#test().
+// ^^^^ definition scip-java maven . . snapshots/KotlinClass#test().
// display_name test
// signature_documentation java void test() throws Class
// kind Method
-// ^^^^^ reference semanticdb maven . . snapshots/Class#
+// ^^^^^ reference scip-java maven . . snapshots/Class#
throw new Class(1, "");
-// ^^^^^ reference semanticdb maven . . snapshots/Class#``().
+// ^^^^^ reference scip-java maven . . snapshots/Class#``().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/KotlinClass#test().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/KotlinClass#test().
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/KotlinClass#other().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/KotlinClass#other().
void other() throws Class {
-// ^^^^^ definition semanticdb maven . . snapshots/KotlinClass#other().
+// ^^^^^ definition scip-java maven . . snapshots/KotlinClass#other().
// display_name other
// signature_documentation java void other() throws Class
// kind Method
-// ^^^^^ reference semanticdb maven . . snapshots/Class#
+// ^^^^^ reference scip-java maven . . snapshots/Class#
throw new Class(1);
-// ^^^^^ reference semanticdb maven . . snapshots/Class#``(+2).
+// ^^^^^ reference scip-java maven . . snapshots/Class#``(+2).
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/KotlinClass#other().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/KotlinClass#other().
}
-//⌃ enclosing_range_end semanticdb maven . . snapshots/KotlinClass#
+//⌃ enclosing_range_end scip-java maven . . snapshots/KotlinClass#
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinLambdas.java b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinLambdas.java
index 4a57bc1d6..b952e169a 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinLambdas.java
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/KotlinLambdas.java
@@ -1,43 +1,43 @@
package snapshots;
import kotlin.collections.CollectionsKt;
-// ^^^^^^ reference semanticdb maven . . kotlin/
-// ^^^^^^^^^^^ reference semanticdb maven . . kotlin/collections/
-// ^^^^^^^^^^^^^ reference semanticdb maven . . kotlin/collections/CollectionsKt#
+// ^^^^^^ reference scip-java maven . . kotlin/
+// ^^^^^^^^^^^ reference scip-java maven . . kotlin/collections/
+// ^^^^^^^^^^^^^ reference scip-java maven . . kotlin/collections/CollectionsKt#
import kotlin.text.StringsKt;
-// ^^^^^^ reference semanticdb maven . . kotlin/
-// ^^^^ reference semanticdb maven . . kotlin/text/
-// ^^^^^^^^^ reference semanticdb maven . . kotlin/text/StringsKt#
+// ^^^^^^ reference scip-java maven . . kotlin/
+// ^^^^ reference scip-java maven . . kotlin/text/
+// ^^^^^^^^^ reference scip-java maven . . kotlin/text/StringsKt#
-//⌄ enclosing_range_start semanticdb maven . . snapshots/KotlinLambdas#
+//⌄ enclosing_range_start scip-java maven . . snapshots/KotlinLambdas#
public class KotlinLambdas {
-// ^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/KotlinLambdas#
+// ^^^^^^^^^^^^^ definition scip-java maven . . snapshots/KotlinLambdas#
// display_name KotlinLambdas
// signature_documentation java public class KotlinLambdas
// kind Class
-// ^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/KotlinLambdas#``().
+// ^^^^^^^^^^^^^ definition scip-java maven . . snapshots/KotlinLambdas#``().
// display_name
// signature_documentation java public KotlinLambdas()
// kind Constructor
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/KotlinLambdas#test().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/KotlinLambdas#test().
public void test() {
-// ^^^^ definition semanticdb maven . . snapshots/KotlinLambdas#test().
+// ^^^^ definition scip-java maven . . snapshots/KotlinLambdas#test().
// display_name test
// signature_documentation java public void test()
// kind Method
LambdasKt.getX(); // TODO figure out emit getX on kotlin side
-// ^^^^^^^^^ reference semanticdb maven . . snapshots/LambdasKt#
-// ^^^^ reference semanticdb maven . . snapshots/LambdasKt#getX().
+// ^^^^^^^^^ reference scip-java maven . . snapshots/LambdasKt#
+// ^^^^ reference scip-java maven . . snapshots/LambdasKt#getX().
kotlin.collections.CollectionsKt.listOf();
-// ^^^^^^ reference semanticdb maven . . kotlin/
-// ^^^^^^^^^^^ reference semanticdb maven . . kotlin/collections/
-// ^^^^^^^^^^^^^ reference semanticdb maven . . kotlin/collections/CollectionsKt#
-// ^^^^^^ reference semanticdb maven . . kotlin/collections/CollectionsKt__CollectionsKt#listOf().
+// ^^^^^^ reference scip-java maven . . kotlin/
+// ^^^^^^^^^^^ reference scip-java maven . . kotlin/collections/
+// ^^^^^^^^^^^^^ reference scip-java maven . . kotlin/collections/CollectionsKt#
+// ^^^^^^ reference scip-java maven . . kotlin/collections/CollectionsKt__CollectionsKt#listOf().
FunctionsKt.sampleText("");
-// ^^^^^^^^^^^ reference semanticdb maven . . snapshots/FunctionsKt#
-// ^^^^^^^^^^ reference semanticdb maven . . snapshots/FunctionsKt#sampleText().
+// ^^^^^^^^^^^ reference scip-java maven . . snapshots/FunctionsKt#
+// ^^^^^^^^^^ reference scip-java maven . . snapshots/FunctionsKt#sampleText().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/KotlinLambdas#test().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/KotlinLambdas#test().
}
-//⌃ enclosing_range_end semanticdb maven . . snapshots/KotlinLambdas#
+//⌃ enclosing_range_end scip-java maven . . snapshots/KotlinLambdas#
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ObjectKtConsumer.java b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ObjectKtConsumer.java
index 8bbb54604..a9c03cefd 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ObjectKtConsumer.java
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/java/snapshots/ObjectKtConsumer.java
@@ -1,26 +1,26 @@
package snapshots;
-//⌄ enclosing_range_start semanticdb maven . . snapshots/ObjectKtConsumer#
+//⌄ enclosing_range_start scip-java maven . . snapshots/ObjectKtConsumer#
public class ObjectKtConsumer {
-// ^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/ObjectKtConsumer#
+// ^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/ObjectKtConsumer#
// display_name ObjectKtConsumer
// signature_documentation java public class ObjectKtConsumer
// kind Class
-// ^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/ObjectKtConsumer#``().
+// ^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/ObjectKtConsumer#``().
// display_name
// signature_documentation java public ObjectKtConsumer()
// kind Constructor
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/ObjectKtConsumer#run().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/ObjectKtConsumer#run().
public static void run() {
-// ^^^ definition semanticdb maven . . snapshots/ObjectKtConsumer#run().
+// ^^^ definition scip-java maven . . snapshots/ObjectKtConsumer#run().
// display_name run
// signature_documentation java public static void run()
// kind StaticMethod
ObjectKt.INSTANCE.fail("boom");
-// ^^^^^^^^ reference semanticdb maven . . snapshots/ObjectKt#
-// ^^^^^^^^ reference semanticdb maven . . snapshots/ObjectKt#INSTANCE.
-// ^^^^ reference semanticdb maven . . snapshots/ObjectKt#fail().
+// ^^^^^^^^ reference scip-java maven . . snapshots/ObjectKt#
+// ^^^^^^^^ reference scip-java maven . . snapshots/ObjectKt#INSTANCE.
+// ^^^^ reference scip-java maven . . snapshots/ObjectKt#fail().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/ObjectKtConsumer#run().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/ObjectKtConsumer#run().
}
-//⌃ enclosing_range_end semanticdb maven . . snapshots/ObjectKtConsumer#
+//⌃ enclosing_range_end scip-java maven . . snapshots/ObjectKtConsumer#
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/Class.kt b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/Class.kt
index 57939c894..b99c5cbb0 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/Class.kt
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/Class.kt
@@ -1,129 +1,146 @@
package snapshots
-// ^^^^^^^^^ reference semanticdb maven . . snapshots/
+// ^^^^^^^^^ reference scip-java maven . . snapshots/
-//⌄ enclosing_range_start semanticdb maven . . snapshots/Class#
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#``().
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#``().(banana)
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#banana.
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#getBanana().
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#setBanana().
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#setBanana().(value)
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#``().(apple)
+//⌄ enclosing_range_start scip-java maven . . snapshots/Class#
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#``().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#``().(banana)
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#banana.
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#getBanana().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#setBanana().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#setBanana().(value)
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#``().(apple)
class Class constructor(private var banana: Int, apple: String) :
-// ^^^^^ definition semanticdb maven . . snapshots/Class#
+// ^^^^^ definition scip-java maven . . snapshots/Class#
// display_name Class
-// documentation ```kotlin\npublic final class Class : Throwable\n```
-// relationship is_reference is_implementation semanticdb maven . . kotlin/Throwable#
-// ^^^^^^^^^^^ definition semanticdb maven . . snapshots/Class#``().
+// signature_documentation kotlin public final class Class : Throwable
+// kind Class
+// relationship is_implementation scip-java maven . . kotlin/Throwable#
+// ^^^^^^^^^^^ definition scip-java maven . . snapshots/Class#``().
// display_name Class
-// documentation ```kotlin\npublic constructor(banana: Int, apple: String): Class\n```
-// ^^^^^^ definition semanticdb maven . . snapshots/Class#``().(banana)
+// signature_documentation kotlin public constructor(banana: Int, apple: String): Class
+// kind Constructor
+// ^^^^^^ definition scip-java maven . . snapshots/Class#``().(banana)
// display_name banana
-// documentation ```kotlin\nbanana: Int\n```
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#``().(banana)
-// ^^^^^^ definition semanticdb maven . . snapshots/Class#banana.
+// signature_documentation kotlin banana: Int
+// kind Parameter
+// ^^^^^^ reference scip-java maven . . snapshots/Class#``().(banana)
+// ^^^^^^ definition scip-java maven . . snapshots/Class#banana.
// display_name banana
-// documentation ```kotlin\nprivate final var banana: Int\n```
-// ^^^^^^ definition semanticdb maven . . snapshots/Class#getBanana().
+// signature_documentation kotlin private final var banana: Int
+// kind Property
+// ^^^^^^ definition scip-java maven . . snapshots/Class#getBanana().
// display_name banana
-// documentation ```kotlin\nprivate get(): Int\n```
-// ^^^^^^ definition semanticdb maven . . snapshots/Class#setBanana().
+// signature_documentation kotlin private get(): Int
+// kind Method
+// ^^^^^^ definition scip-java maven . . snapshots/Class#setBanana().
// display_name banana
-// documentation ```kotlin\nprivate set(value: Int): Unit\n```
-// ^^^^^^ definition semanticdb maven . . snapshots/Class#setBanana().(value)
+// signature_documentation kotlin private set(value: Int): Unit
+// kind Method
+// ^^^^^^ definition scip-java maven . . snapshots/Class#setBanana().(value)
// display_name value
-// documentation ```kotlin\nvalue: Int\n```
-// ^^^ reference semanticdb maven . . kotlin/Int#
-// ^^^^^ definition semanticdb maven . . snapshots/Class#``().(apple)
+// signature_documentation kotlin value: Int
+// kind Parameter
+// ^^^ reference scip-java maven . . kotlin/Int#
+// ^^^^^ definition scip-java maven . . snapshots/Class#``().(apple)
// display_name apple
-// documentation ```kotlin\napple: String\n```
-// ^^^^^^ reference semanticdb maven . . kotlin/String#
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#``().(banana)
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#banana.
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#getBanana().
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#setBanana().
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#setBanana().(value)
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#``().(apple)
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#``().
+// signature_documentation kotlin apple: String
+// kind Parameter
+// ^^^^^^ reference scip-java maven . . kotlin/String#
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#``().(banana)
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#banana.
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#getBanana().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#setBanana().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#setBanana().(value)
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#``().(apple)
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#``().
Throwable(banana.toString() + apple) {
-// ^^^^^^^^^ reference semanticdb maven . . kotlin/Throwable#
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#``().(banana)
-// ^^^^^^^^ reference semanticdb maven . . kotlin/Int#toString().
-// ^ reference semanticdb maven . . kotlin/String#plus().
-// ^^^^^ reference semanticdb maven . . snapshots/Class#``().(apple)
+// ^^^^^^^^^ reference scip-java maven . . kotlin/Throwable#
+// ^^^^^^ reference scip-java maven . . snapshots/Class#``().(banana)
+// ^^^^^^^^ reference scip-java maven . . kotlin/Int#toString().
+// ^ reference scip-java maven . . kotlin/String#plus().
+// ^^^^^ reference scip-java maven . . snapshots/Class#``().(apple)
init {
println("")
-// ^^^^^^^ reference semanticdb maven . . kotlin/io/println().
+// ^^^^^^^ reference scip-java maven . . kotlin/io/println().
}
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#asdf.
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#getAsdf().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#asdf.
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#getAsdf().
val asdf =
-// ^^^^ definition semanticdb maven . . snapshots/Class#asdf.
+// ^^^^ definition scip-java maven . . snapshots/Class#asdf.
// display_name asdf
-// documentation ```kotlin\npublic final val asdf: Any\n```
-// ^^^^ definition semanticdb maven . . snapshots/Class#getAsdf().
+// signature_documentation kotlin public final val asdf: Any
+// kind Property
+// ^^^^ definition scip-java maven . . snapshots/Class#getAsdf().
// display_name asdf
-// documentation ```kotlin\npublic get(): Any\n```
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/``#
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/``#``().
+// signature_documentation kotlin public get(): Any
+// kind Method
+// ⌄ enclosing_range_start scip-java maven . . snapshots/``#
+// ⌄ enclosing_range_start scip-java maven . . snapshots/``#``().
object {
-// ^^^^^^ definition semanticdb maven . . snapshots/``#
+// ^^^^^^ definition scip-java maven . . snapshots/``#
// display_name
-// documentation ```kotlin\nobject : Any\n```
-// ^^^^^^ definition semanticdb maven . . snapshots/``#``().
+// signature_documentation kotlin object : Any
+// kind Object
+// ^^^^^^ definition scip-java maven . . snapshots/``#``().
// display_name
-// documentation ```kotlin\nprivate constructor(): \n```
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/``#doStuff().
+// signature_documentation kotlin private constructor():
+// kind Constructor
+// ⌄ enclosing_range_start scip-java maven . . snapshots/``#doStuff().
fun doStuff() = Unit
-// ^^^^^^^ definition semanticdb maven . . snapshots/``#doStuff().
+// ^^^^^^^ definition scip-java maven . . snapshots/``#doStuff().
// display_name doStuff
-// documentation ```kotlin\npublic final fun doStuff(): Unit\n```
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/``#doStuff().
+// signature_documentation kotlin public final fun doStuff(): Unit
+// kind Method
+// ⌃ enclosing_range_end scip-java maven . . snapshots/``#doStuff().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#asdf.
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#getAsdf().
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/``#
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/``#``().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#asdf.
+// ⌃ enclosing_range_end scip-java maven . . snapshots/``#
+// ⌃ enclosing_range_end scip-java maven . . snapshots/``#``().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#getAsdf().
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#``(+1).
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#``(+1).
constructor() : this(1, "")
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/Class#``(+1).
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/Class#``(+1).
// display_name Class
-// documentation ```kotlin\npublic constructor(): Class\n```
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#``(+1).
+// signature_documentation kotlin public constructor(): Class
+// kind Constructor
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#``(+1).
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#``(+2).
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#``(+2).(banana)
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#``(+2).
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#``(+2).(banana)
constructor(banana: Int) : this(banana, "")
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/Class#``(+2).
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/Class#``(+2).
// display_name Class
-// documentation ```kotlin\npublic constructor(banana: Int): Class\n```
-// ^^^^^^ definition semanticdb maven . . snapshots/Class#``(+2).(banana)
+// signature_documentation kotlin public constructor(banana: Int): Class
+// kind Constructor
+// ^^^^^^ definition scip-java maven . . snapshots/Class#``(+2).(banana)
// display_name banana
-// documentation ```kotlin\nbanana: Int\n```
-// ^^^ reference semanticdb maven . . kotlin/Int#
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#``(+2).(banana)
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#``(+2).(banana)
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#``(+2).
+// signature_documentation kotlin banana: Int
+// kind Parameter
+// ^^^ reference scip-java maven . . kotlin/Int#
+// ^^^^^^ reference scip-java maven . . snapshots/Class#``(+2).(banana)
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#``(+2).(banana)
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#``(+2).
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/Class#run().
+// ⌄ enclosing_range_start scip-java maven . . snapshots/Class#run().
fun run() {
-// ^^^ definition semanticdb maven . . snapshots/Class#run().
+// ^^^ definition scip-java maven . . snapshots/Class#run().
// display_name run
-// documentation ```kotlin\npublic final fun run(): Unit\n```
+// signature_documentation kotlin public final fun run(): Unit
+// kind Method
println(Class::class)
-// ^^^^^^^ reference semanticdb maven . . kotlin/io/println().
+// ^^^^^^^ reference scip-java maven . . kotlin/io/println().
println("I eat $banana for lunch")
-// ^^^^^^^ reference semanticdb maven . . kotlin/io/println().
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#banana.
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#getBanana().
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#setBanana().
+// ^^^^^^^ reference scip-java maven . . kotlin/io/println().
+// ^^^^^^ reference scip-java maven . . snapshots/Class#banana.
+// ^^^^^^ reference scip-java maven . . snapshots/Class#getBanana().
+// ^^^^^^ reference scip-java maven . . snapshots/Class#setBanana().
banana = 42
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#banana.
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#getBanana().
-// ^^^^^^ reference semanticdb maven . . snapshots/Class#setBanana().
+// ^^^^^^ reference scip-java maven . . snapshots/Class#banana.
+// ^^^^^^ reference scip-java maven . . snapshots/Class#getBanana().
+// ^^^^^^ reference scip-java maven . . snapshots/Class#setBanana().
}
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/Class#run().
+// ⌃ enclosing_range_end scip-java maven . . snapshots/Class#run().
}
-//⌃ enclosing_range_end semanticdb maven . . snapshots/Class#
+//⌃ enclosing_range_end scip-java maven . . snapshots/Class#
diff --git a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/CompanionOwner.kt b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/CompanionOwner.kt
index a5a386101..6ffe782a6 100644
--- a/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/CompanionOwner.kt
+++ b/semanticdb-kotlinc/minimized/src/generatedSnapshots/resources/semanticdb-kotlinc/minimized/src/main/kotlin/snapshots/CompanionOwner.kt
@@ -1,44 +1,50 @@
package snapshots
-// ^^^^^^^^^ reference semanticdb maven . . snapshots/
+// ^^^^^^^^^ reference scip-java maven . . snapshots/
-//⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionOwner#
-//⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionOwner#``().
+//⌄ enclosing_range_start scip-java maven . . snapshots/CompanionOwner#
+//⌄ enclosing_range_start scip-java maven . . snapshots/CompanionOwner#``().
class CompanionOwner {
-// ^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/CompanionOwner#
+// ^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/CompanionOwner#
// display_name CompanionOwner
-// documentation ```kotlin\npublic final class CompanionOwner : Any\n```
-// ^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/CompanionOwner#``().
+// signature_documentation kotlin public final class CompanionOwner : Any
+// kind Class
+// ^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/CompanionOwner#``().
// display_name CompanionOwner
-// documentation ```kotlin\npublic constructor(): CompanionOwner\n```
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionOwner#Companion#
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionOwner#Companion#``().
+// signature_documentation kotlin public constructor(): CompanionOwner
+// kind Constructor
+// ⌄ enclosing_range_start scip-java maven . . snapshots/CompanionOwner#Companion#
+// ⌄ enclosing_range_start scip-java maven . . snapshots/CompanionOwner#Companion#``().
companion object {
-// ^^^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/CompanionOwner#Companion# 2:3
+// ^^^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/CompanionOwner#Companion# 2:3
// display_name Companion
-// documentation ```kotlin\npublic final companion object Companion : Any\n```
-// ^^^^^^^^^^^^^^^^^^ definition semanticdb maven . . snapshots/CompanionOwner#Companion#``(). 2:3
+// signature_documentation kotlin public final companion object Companion : Any
+// kind Object
+// ^^^^^^^^^^^^^^^^^^ definition scip-java maven . . snapshots/CompanionOwner#Companion#``(). 2:3
// display_name Companion
-// documentation ```kotlin\nprivate constructor(): CompanionOwner.Companion\n```
-// ⌄ enclosing_range_start semanticdb maven . . snapshots/CompanionOwner#Companion#create().
+// signature_documentation kotlin private constructor(): CompanionOwner.Companion
+// kind Constructor
+// ⌄ enclosing_range_start scip-java maven . . snapshots/CompanionOwner#Companion#create().
fun create(): CompanionOwner = CompanionOwner()
-// ^^^^^^ definition semanticdb maven . . snapshots/CompanionOwner#Companion#create().
+// ^^^^^^ definition scip-java maven . . snapshots/CompanionOwner#Companion#create().
// display_name create
-// documentation ```kotlin\npublic final fun create(): CompanionOwner\n```
-// ^^^^^^^^^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#
-// ^^^^^^^^^^^^^^ reference semanticdb maven . . snapshots/CompanionOwner#``().
-// ⌃ enclosing_range_end semanticdb maven . . snapshots/CompanionOwner#Companion#create().
+// signature_documentation kotlin public final fun create(): CompanionOwner
+// kind Method
+// ^^^^^^^^^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#
+// ^^^^^^^^^^^^^^ reference scip-java maven . . snapshots/CompanionOwner#`