From 03e2859b6c1919ce124ee97e24dde01e6dec71f0 Mon Sep 17 00:00:00 2001 From: jupblb Date: Tue, 30 Jun 2026 16:21:13 +0200 Subject: [PATCH 1/3] Upgrade SCIP bindings to 0.9 --- MODULE.bazel | 2 +- gradle/libs.versions.toml | 2 +- .../scip_aggregator/ScipAggregator.java | 7 +- .../sourcegraph/scip_javac/ScipVisitor.java | 26 ++-- .../scip_kotlinc/ScipTextDocumentBuilder.kt | 23 +-- .../scip_kotlinc/test/ScipBuilders.kt | 26 ++-- .../sourcegraph/scip/ScipDocumentBuilder.java | 17 +-- .../java/com/sourcegraph/scip/ScipRanges.java | 139 ++++++++++++++++++ 8 files changed, 187 insertions(+), 55 deletions(-) create mode 100644 scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java diff --git a/MODULE.bazel b/MODULE.bazel index 8a9a0d285..728e38ed2 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -10,7 +10,7 @@ maven.install( artifacts = [ "com.google.protobuf:protobuf-java-util:4.34.2", "org.projectlombok:lombok:1.18.46", - "org.scip-code:scip-java-bindings:0.8.0", + "org.scip-code:scip-java-bindings:0.9.0", ], known_contributing_modules = ["protobuf"], repositories = ["https://repo1.maven.org/maven2"], diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b09deff11..156c064b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ maven-plugin-api = "3.6.3" maven-project = "2.2.1" protobuf = "4.34.2" protobuf-plugin = "0.10.0" -scip-bindings = "0.8.0" +scip-bindings = "0.9.0" shadow = "9.4.3" spotless = "8.7.0" vanniktech-maven-publish = "0.35.0" diff --git a/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java b/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java index 04f027144..595174336 100644 --- a/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java +++ b/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java @@ -1,6 +1,7 @@ package com.sourcegraph.scip_aggregator; import com.google.protobuf.CodedInputStream; +import com.sourcegraph.scip.ScipRanges; import com.sourcegraph.scip.ScipSymbols; import java.io.IOException; import java.nio.file.FileSystems; @@ -153,12 +154,10 @@ private Document rewriteDocument( for (Occurrence occ : shard.getOccurrencesList()) { Occurrence.Builder rebuilt = Occurrence.newBuilder() - .addAllRange(occ.getRangeList()) .setSymbol(rewriter.rewrite(occ.getSymbol())) .setSymbolRoles(occ.getSymbolRoles()); - if (occ.getEnclosingRangeCount() > 0) { - rebuilt.addAllEnclosingRange(occ.getEnclosingRangeList()); - } + ScipRanges.copyRange(occ, rebuilt); + ScipRanges.copyEnclosingRange(occ, rebuilt); out.addOccurrences(rebuilt); } diff --git a/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java b/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java index 1878da466..8fce666df 100644 --- a/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java +++ b/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java @@ -2,6 +2,8 @@ import com.sourcegraph.scip.LocalSymbolsCache; import com.sourcegraph.scip.ScipDocumentBuilder; +import com.sourcegraph.scip.ScipRanges; +import com.sourcegraph.scip.ScipRanges.Range; import com.sourcegraph.scip.ScipSymbols; import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.ClassTree; @@ -182,7 +184,7 @@ private void resolveMethodTree(MethodTree node, TreePath treePath) { private void resolveVariableTree(VariableTree node, TreePath treePath) { Element sym = trees.getElement(treePath); if (sym == null) return; - int[] range = + Range range = emitDefinition(sym, node, sym.getSimpleName(), CompilerRange.FROM_POINT_WITH_TEXT_SEARCH); if (sym.getKind() == ElementKind.ENUM_CONSTANT) { TreePath typeTreePath = nodes.get(node.getInitializer()); @@ -246,8 +248,8 @@ private void resolveNewClassTree(NewClassTree node, TreePath treePath) { // ======================================= // Occurrence + SymbolInformation emission // ======================================= - private int[] emitDefinition(Element sym, Tree tree, Name name, CompilerRange kind) { - int[] range = computeRange(tree, kind, sym, name == null ? null : name.toString()); + private Range emitDefinition(Element sym, Tree tree, Name name, CompilerRange kind) { + Range range = computeRange(tree, kind, sym, name == null ? null : name.toString()); if (range == null) return null; emitOccurrence(sym, range, SymbolRole.Definition_VALUE, computeEnclosingRange(tree)); declTrees.put(sym, tree); @@ -256,18 +258,18 @@ private int[] emitDefinition(Element sym, Tree tree, Name name, CompilerRange ki } private void emitReference(Element sym, Tree tree, Name name, CompilerRange kind) { - int[] range = computeRange(tree, kind, sym, name == null ? null : name.toString()); + Range range = computeRange(tree, kind, sym, name == null ? null : name.toString()); if (range == null) return; emitOccurrence(sym, range, 0 /* reference */, null); } - private void emitOccurrence(Element sym, int[] range, int role, int[] enclosingRange) { + private void emitOccurrence(Element sym, Range range, int role, Range enclosingRange) { String symbol = scipSymbol(sym); if (symbol.isEmpty()) return; Occurrence.Builder b = Occurrence.newBuilder().setSymbol(symbol).setSymbolRoles(role); - for (int v : range) b.addRange(v); + ScipRanges.setRange(b, range); if (enclosingRange != null) { - for (int v : enclosingRange) b.addEnclosingRange(v); + ScipRanges.setEnclosingRange(b, enclosingRange); } documentBuilder.addOccurrence(b.build()); } @@ -360,7 +362,7 @@ private SymbolInformation.Kind scipKind(Element sym) { // ======================================= // Source position / range computation // ======================================= - private int[] computeRange(Tree tree, CompilerRange kind, Element sym, String name) { + private Range computeRange(Tree tree, CompilerRange kind, Element sym, String name) { if (sym == null) return null; SourcePositions sourcePositions = trees.getSourcePositions(); int start = (int) sourcePositions.getStartPosition(compUnitTree, tree); @@ -394,7 +396,7 @@ private int[] computeRange(Tree tree, CompilerRange kind, Element sym, String na return lineMapRange(start, end); } - private int[] computeEnclosingRange(Tree tree) { + private Range computeEnclosingRange(Tree tree) { if (tree == null) return null; TreePath path = nodes.get(tree); if (path == null) return null; @@ -413,7 +415,7 @@ private int[] computeEnclosingRange(Tree tree) { return lineMapRange(start, end); } - private int[] lineMapRange(int start, int end) { + private Range lineMapRange(int start, int end) { if (start == Diagnostic.NOPOS || end == Diagnostic.NOPOS || end <= start) return null; LineMap lineMap = compUnitTree.getLineMap(); int startLine = (int) lineMap.getLineNumber(start) - 1; @@ -431,8 +433,8 @@ private int[] lineMapRange(int start, int end) { endChar -= count * 7; } - if (startLine == endLine) return new int[] {startLine, startChar, endChar}; - return new int[] {startLine, startChar, endLine, endChar}; + if (startLine == endLine) return ScipRanges.singleLineRange(startLine, startChar, endChar); + return ScipRanges.range(startLine, startChar, endLine, endChar); } // ======================================= diff --git a/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt b/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt index 778fb7b1e..f85822144 100644 --- a/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt +++ b/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt @@ -1,6 +1,8 @@ package com.sourcegraph.scip_kotlinc import com.sourcegraph.scip.ScipDocumentBuilder +import com.sourcegraph.scip.ScipRanges +import com.sourcegraph.scip.ScipRanges.Range import com.sourcegraph.scip.ScipShardPaths import java.nio.file.Path import java.nio.file.Paths @@ -22,7 +24,6 @@ import org.scip_code.scip.Document import org.scip_code.scip.Occurrence import org.scip_code.scip.SymbolInformation import org.scip_code.scip.SymbolRole -import org.scip_code.scip.occurrence import org.scip_code.scip.relationship import org.scip_code.scip.signature import org.scip_code.scip.symbolInformation @@ -98,29 +99,29 @@ class ScipTextDocumentBuilder( element: KtSourceElement, isDefinition: Boolean, enclosingSource: KtSourceElement?, - ): Occurrence = occurrence { - this.symbol = symbol.toString() - if (isDefinition) symbolRoles = SymbolRole.Definition.number - range += range(element).asIterable() + ): Occurrence { + val builder = Occurrence.newBuilder().setSymbol(symbol.toString()) + if (isDefinition) builder.setSymbolRoles(SymbolRole.Definition.number) + ScipRanges.setRange(builder, range(element)) if (enclosingSource != null) { - enclosingRange += enclosingRange(enclosingSource).asIterable() + ScipRanges.setEnclosingRange(builder, enclosingRange(enclosingSource)) } + return builder.build() } - private fun range(element: KtSourceElement): IntArray { + private fun range(element: KtSourceElement): Range { val line = lineMap.lineNumber(element) - 1 val startCol = lineMap.startCharacter(element) val endCol = lineMap.endCharacter(element) - return intArrayOf(line, startCol, endCol) + return ScipRanges.singleLineRange(line, startCol, endCol) } - private fun enclosingRange(element: KtSourceElement): IntArray { + private fun enclosingRange(element: KtSourceElement): Range { val startLine = lineMap.lineNumber(element) - 1 val startCol = lineMap.startCharacter(element) val endLine = lineMap.lineNumberForOffset(element.endOffset) - 1 val endCol = lineMap.columnForOffset(element.endOffset) - return if (startLine == endLine) intArrayOf(startLine, startCol, endCol) - else intArrayOf(startLine, startCol, endLine, endCol) + return ScipRanges.range(startLine, startCol, endLine, endCol) } private fun relativePath(): String = diff --git a/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt b/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt index ff579e796..8010d337a 100644 --- a/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt +++ b/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt @@ -1,9 +1,10 @@ package com.sourcegraph.scip_kotlinc.test +import com.sourcegraph.scip.ScipRanges +import com.sourcegraph.scip.ScipRanges.Range import org.scip_code.scip.Occurrence import org.scip_code.scip.SymbolInformation import org.scip_code.scip.SymbolRole -import org.scip_code.scip.occurrence import org.scip_code.scip.relationship import org.scip_code.scip.signature import org.scip_code.scip.symbolInformation @@ -38,10 +39,9 @@ class ScipRangeBuilder { var endLine: Int = -1 var endCharacter: Int = 0 - internal fun toIntList(): List { + internal fun toScipRange(): Range { val line = if (endLine < 0) startLine else endLine - return if (line == startLine) listOf(startLine, startCharacter, endCharacter) - else listOf(startLine, startCharacter, line, endCharacter) + return ScipRanges.range(startLine, startCharacter, line, endCharacter) } } @@ -49,22 +49,22 @@ class ScipRangeBuilder { class ScipOccurrenceBuilder { var role: Int = REFERENCE var symbol: String = "" - private var range: List? = null - private var enclosingRange: List? = null + private var range: Range? = null + private var enclosingRange: Range? = null fun range(block: ScipRangeBuilder.() -> Unit) { - range = ScipRangeBuilder().apply(block).toIntList() + range = ScipRangeBuilder().apply(block).toScipRange() } fun enclosingRange(block: ScipRangeBuilder.() -> Unit) { - enclosingRange = ScipRangeBuilder().apply(block).toIntList() + enclosingRange = ScipRangeBuilder().apply(block).toScipRange() } - internal fun build(): Occurrence = occurrence { - symbol = this@ScipOccurrenceBuilder.symbol - symbolRoles = role - this@ScipOccurrenceBuilder.range?.let { range += it } - this@ScipOccurrenceBuilder.enclosingRange?.let { enclosingRange += it } + internal fun build(): Occurrence { + val builder = Occurrence.newBuilder().setSymbol(symbol).setSymbolRoles(role) + range?.let { ScipRanges.setRange(builder, it) } + enclosingRange?.let { ScipRanges.setEnclosingRange(builder, it) } + return builder.build() } } diff --git a/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java b/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java index e9c53b858..34afa54c3 100644 --- a/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java +++ b/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java @@ -1,7 +1,6 @@ package com.sourcegraph.scip; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; @@ -21,8 +20,8 @@ */ public final class ScipDocumentBuilder { private static final Comparator OCCURRENCE_ORDER = - Comparator.comparingInt(o -> rangeStartLine(o)) - .thenComparingInt(o -> rangeStartCharacter(o)); + Comparator.comparingInt(ScipRanges::rangeStartLine) + .thenComparingInt(ScipRanges::rangeStartCharacter); private final Map occurrences = new LinkedHashMap<>(); private final Map symbols = new LinkedHashMap<>(); @@ -49,21 +48,13 @@ public Document build(String language, String relativePath, String text) { .build(); } - private static int rangeStartLine(Occurrence occurrence) { - return occurrence.getRangeCount() > 0 ? occurrence.getRange(0) : 0; - } - - private static int rangeStartCharacter(Occurrence occurrence) { - return occurrence.getRangeCount() > 1 ? occurrence.getRange(1) : 0; - } - private static final class OccurrenceKey { - private final List range; + private final ScipRanges.Range range; private final String symbol; private final int roles; OccurrenceKey(Occurrence occurrence) { - this.range = Collections.unmodifiableList(new ArrayList<>(occurrence.getRangeList())); + this.range = ScipRanges.range(occurrence); this.symbol = occurrence.getSymbol(); this.roles = occurrence.getSymbolRoles(); } diff --git a/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java new file mode 100644 index 000000000..9d28c3d7b --- /dev/null +++ b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java @@ -0,0 +1,139 @@ +package com.sourcegraph.scip; + +import org.scip_code.scip.MultiLineRange; +import org.scip_code.scip.Occurrence; +import org.scip_code.scip.SingleLineRange; + +/** Helpers for reading and writing SCIP occurrence ranges. */ +public final class ScipRanges { + private ScipRanges() {} + + public static Range singleLineRange(int line, int startCharacter, int endCharacter) { + return new Range(line, startCharacter, line, endCharacter); + } + + public static Range range(int startLine, int startCharacter, int endLine, int endCharacter) { + return new Range(startLine, startCharacter, endLine, endCharacter); + } + + /** Sets the typed {@code range} oneof on {@code builder}. */ + public static Occurrence.Builder setRange(Occurrence.Builder builder, Range range) { + clearRange(builder); + if (range.isSingleLine()) { + builder.setSingleLineRange(range.toSingleLineRange()); + } else { + builder.setMultiLineRange(range.toMultiLineRange()); + } + return builder; + } + + /** Sets the typed {@code enclosing_range} oneof on {@code builder}. */ + public static Occurrence.Builder setEnclosingRange(Occurrence.Builder builder, Range range) { + clearEnclosingRange(builder); + if (range.isSingleLine()) { + builder.setSingleLineEnclosingRange(range.toSingleLineRange()); + } else { + builder.setMultiLineEnclosingRange(range.toMultiLineRange()); + } + return builder; + } + + /** Copies the preferred range encoding from {@code source} to {@code target}. */ + public static Occurrence.Builder copyRange(Occurrence source, Occurrence.Builder target) { + clearRange(target); + switch (source.getTypedRangeCase()) { + case SINGLE_LINE_RANGE: + target.setSingleLineRange(source.getSingleLineRange()); + return target; + case MULTI_LINE_RANGE: + target.setMultiLineRange(source.getMultiLineRange()); + return target; + case TYPEDRANGE_NOT_SET: + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + + /** Copies the preferred enclosing range encoding from {@code source} to {@code target}. */ + public static Occurrence.Builder copyEnclosingRange( + Occurrence source, Occurrence.Builder target) { + clearEnclosingRange(target); + switch (source.getTypedEnclosingRangeCase()) { + case SINGLE_LINE_ENCLOSING_RANGE: + target.setSingleLineEnclosingRange(source.getSingleLineEnclosingRange()); + return target; + case MULTI_LINE_ENCLOSING_RANGE: + target.setMultiLineEnclosingRange(source.getMultiLineEnclosingRange()); + return target; + case TYPEDENCLOSINGRANGE_NOT_SET: + return target; + } + return target; + } + + public static Range range(Occurrence occurrence) { + switch (occurrence.getTypedRangeCase()) { + case SINGLE_LINE_RANGE: + return Range.from(occurrence.getSingleLineRange()); + case MULTI_LINE_RANGE: + return Range.from(occurrence.getMultiLineRange()); + case TYPEDRANGE_NOT_SET: + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + + public static int rangeStartLine(Occurrence occurrence) { + return range(occurrence).startLine(); + } + + public static int rangeStartCharacter(Occurrence occurrence) { + return range(occurrence).startCharacter(); + } + + private static void clearRange(Occurrence.Builder builder) { + builder.clearSingleLineRange(); + builder.clearMultiLineRange(); + } + + private static void clearEnclosingRange(Occurrence.Builder builder) { + builder.clearSingleLineEnclosingRange(); + builder.clearMultiLineEnclosingRange(); + } + + public record Range(int startLine, int startCharacter, int endLine, int endCharacter) { + private static Range from(SingleLineRange range) { + return new Range( + range.getLine(), range.getStartCharacter(), range.getLine(), range.getEndCharacter()); + } + + private static Range from(MultiLineRange range) { + return new Range( + range.getStartLine(), + range.getStartCharacter(), + range.getEndLine(), + range.getEndCharacter()); + } + + private boolean isSingleLine() { + return startLine == endLine; + } + + private SingleLineRange toSingleLineRange() { + return SingleLineRange.newBuilder() + .setLine(startLine) + .setStartCharacter(startCharacter) + .setEndCharacter(endCharacter) + .build(); + } + + private MultiLineRange toMultiLineRange() { + return MultiLineRange.newBuilder() + .setStartLine(startLine) + .setStartCharacter(startCharacter) + .setEndLine(endLine) + .setEndCharacter(endCharacter) + .build(); + } + } +} From 71691f81e560a2048a48c45d5ae7d248d6ec5f80 Mon Sep 17 00:00:00 2001 From: jupblb Date: Tue, 30 Jun 2026 17:28:25 +0200 Subject: [PATCH 2/3] Simplify typed range helpers --- .../scip_aggregator/ScipAggregator.java | 16 +++- .../sourcegraph/scip_javac/ScipVisitor.java | 12 ++- .../scip_kotlinc/ScipTextDocumentBuilder.kt | 11 ++- .../scip_kotlinc/test/ScipBuilders.kt | 10 ++- .../java/com/sourcegraph/scip/ScipRanges.java | 75 ++----------------- 5 files changed, 46 insertions(+), 78 deletions(-) diff --git a/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java b/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java index 595174336..845d4d5fb 100644 --- a/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java +++ b/scip-aggregator/src/main/java/com/sourcegraph/scip_aggregator/ScipAggregator.java @@ -1,7 +1,6 @@ package com.sourcegraph.scip_aggregator; import com.google.protobuf.CodedInputStream; -import com.sourcegraph.scip.ScipRanges; import com.sourcegraph.scip.ScipSymbols; import java.io.IOException; import java.nio.file.FileSystems; @@ -156,8 +155,19 @@ private Document rewriteDocument( Occurrence.newBuilder() .setSymbol(rewriter.rewrite(occ.getSymbol())) .setSymbolRoles(occ.getSymbolRoles()); - ScipRanges.copyRange(occ, rebuilt); - ScipRanges.copyEnclosingRange(occ, rebuilt); + switch (occ.getTypedRangeCase()) { + case SINGLE_LINE_RANGE -> rebuilt.setSingleLineRange(occ.getSingleLineRange()); + case MULTI_LINE_RANGE -> rebuilt.setMultiLineRange(occ.getMultiLineRange()); + case TYPEDRANGE_NOT_SET -> + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + switch (occ.getTypedEnclosingRangeCase()) { + case SINGLE_LINE_ENCLOSING_RANGE -> + rebuilt.setSingleLineEnclosingRange(occ.getSingleLineEnclosingRange()); + case MULTI_LINE_ENCLOSING_RANGE -> + rebuilt.setMultiLineEnclosingRange(occ.getMultiLineEnclosingRange()); + case TYPEDENCLOSINGRANGE_NOT_SET -> {} + } out.addOccurrences(rebuilt); } diff --git a/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java b/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java index 8fce666df..f6550e570 100644 --- a/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java +++ b/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java @@ -267,9 +267,17 @@ private void emitOccurrence(Element sym, Range range, int role, Range enclosingR String symbol = scipSymbol(sym); if (symbol.isEmpty()) return; Occurrence.Builder b = Occurrence.newBuilder().setSymbol(symbol).setSymbolRoles(role); - ScipRanges.setRange(b, range); + if (range.isSingleLine()) { + b.setSingleLineRange(range.toSingleLineRange()); + } else { + b.setMultiLineRange(range.toMultiLineRange()); + } if (enclosingRange != null) { - ScipRanges.setEnclosingRange(b, enclosingRange); + if (enclosingRange.isSingleLine()) { + b.setSingleLineEnclosingRange(enclosingRange.toSingleLineRange()); + } else { + b.setMultiLineEnclosingRange(enclosingRange.toMultiLineRange()); + } } documentBuilder.addOccurrence(b.build()); } diff --git a/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt b/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt index f85822144..d26f1b390 100644 --- a/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt +++ b/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt @@ -102,9 +102,16 @@ class ScipTextDocumentBuilder( ): Occurrence { val builder = Occurrence.newBuilder().setSymbol(symbol.toString()) if (isDefinition) builder.setSymbolRoles(SymbolRole.Definition.number) - ScipRanges.setRange(builder, range(element)) + val range = range(element) + if (range.isSingleLine) builder.singleLineRange = range.toSingleLineRange() + else builder.multiLineRange = range.toMultiLineRange() if (enclosingSource != null) { - ScipRanges.setEnclosingRange(builder, enclosingRange(enclosingSource)) + val enclosingRange = enclosingRange(enclosingSource) + if (enclosingRange.isSingleLine) { + builder.singleLineEnclosingRange = enclosingRange.toSingleLineRange() + } else { + builder.multiLineEnclosingRange = enclosingRange.toMultiLineRange() + } } return builder.build() } diff --git a/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt b/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt index 8010d337a..a91f34c22 100644 --- a/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt +++ b/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt @@ -62,8 +62,14 @@ class ScipOccurrenceBuilder { internal fun build(): Occurrence { val builder = Occurrence.newBuilder().setSymbol(symbol).setSymbolRoles(role) - range?.let { ScipRanges.setRange(builder, it) } - enclosingRange?.let { ScipRanges.setEnclosingRange(builder, it) } + range?.let { + if (it.isSingleLine) builder.singleLineRange = it.toSingleLineRange() + else builder.multiLineRange = it.toMultiLineRange() + } + enclosingRange?.let { + if (it.isSingleLine) builder.singleLineEnclosingRange = it.toSingleLineRange() + else builder.multiLineEnclosingRange = it.toMultiLineRange() + } return builder.build() } } diff --git a/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java index 9d28c3d7b..822c159a5 100644 --- a/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java +++ b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java @@ -4,7 +4,7 @@ import org.scip_code.scip.Occurrence; import org.scip_code.scip.SingleLineRange; -/** Helpers for reading and writing SCIP occurrence ranges. */ +/** Helpers for creating and reading typed SCIP occurrence ranges. */ public final class ScipRanges { private ScipRanges() {} @@ -16,61 +16,6 @@ public static Range range(int startLine, int startCharacter, int endLine, int en return new Range(startLine, startCharacter, endLine, endCharacter); } - /** Sets the typed {@code range} oneof on {@code builder}. */ - public static Occurrence.Builder setRange(Occurrence.Builder builder, Range range) { - clearRange(builder); - if (range.isSingleLine()) { - builder.setSingleLineRange(range.toSingleLineRange()); - } else { - builder.setMultiLineRange(range.toMultiLineRange()); - } - return builder; - } - - /** Sets the typed {@code enclosing_range} oneof on {@code builder}. */ - public static Occurrence.Builder setEnclosingRange(Occurrence.Builder builder, Range range) { - clearEnclosingRange(builder); - if (range.isSingleLine()) { - builder.setSingleLineEnclosingRange(range.toSingleLineRange()); - } else { - builder.setMultiLineEnclosingRange(range.toMultiLineRange()); - } - return builder; - } - - /** Copies the preferred range encoding from {@code source} to {@code target}. */ - public static Occurrence.Builder copyRange(Occurrence source, Occurrence.Builder target) { - clearRange(target); - switch (source.getTypedRangeCase()) { - case SINGLE_LINE_RANGE: - target.setSingleLineRange(source.getSingleLineRange()); - return target; - case MULTI_LINE_RANGE: - target.setMultiLineRange(source.getMultiLineRange()); - return target; - case TYPEDRANGE_NOT_SET: - throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); - } - throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); - } - - /** Copies the preferred enclosing range encoding from {@code source} to {@code target}. */ - public static Occurrence.Builder copyEnclosingRange( - Occurrence source, Occurrence.Builder target) { - clearEnclosingRange(target); - switch (source.getTypedEnclosingRangeCase()) { - case SINGLE_LINE_ENCLOSING_RANGE: - target.setSingleLineEnclosingRange(source.getSingleLineEnclosingRange()); - return target; - case MULTI_LINE_ENCLOSING_RANGE: - target.setMultiLineEnclosingRange(source.getMultiLineEnclosingRange()); - return target; - case TYPEDENCLOSINGRANGE_NOT_SET: - return target; - } - return target; - } - public static Range range(Occurrence occurrence) { switch (occurrence.getTypedRangeCase()) { case SINGLE_LINE_RANGE: @@ -91,16 +36,6 @@ public static int rangeStartCharacter(Occurrence occurrence) { return range(occurrence).startCharacter(); } - private static void clearRange(Occurrence.Builder builder) { - builder.clearSingleLineRange(); - builder.clearMultiLineRange(); - } - - private static void clearEnclosingRange(Occurrence.Builder builder) { - builder.clearSingleLineEnclosingRange(); - builder.clearMultiLineEnclosingRange(); - } - public record Range(int startLine, int startCharacter, int endLine, int endCharacter) { private static Range from(SingleLineRange range) { return new Range( @@ -115,11 +50,12 @@ private static Range from(MultiLineRange range) { range.getEndCharacter()); } - private boolean isSingleLine() { + public boolean isSingleLine() { return startLine == endLine; } - private SingleLineRange toSingleLineRange() { + public SingleLineRange toSingleLineRange() { + if (!isSingleLine()) throw new IllegalStateException("expected single-line range"); return SingleLineRange.newBuilder() .setLine(startLine) .setStartCharacter(startCharacter) @@ -127,7 +63,8 @@ private SingleLineRange toSingleLineRange() { .build(); } - private MultiLineRange toMultiLineRange() { + public MultiLineRange toMultiLineRange() { + if (isSingleLine()) throw new IllegalStateException("expected multi-line range"); return MultiLineRange.newBuilder() .setStartLine(startLine) .setStartCharacter(startCharacter) From 93b86b3c4dbc81ef7494b4c852a88ec2324bf168 Mon Sep 17 00:00:00 2001 From: jupblb Date: Tue, 30 Jun 2026 18:05:10 +0200 Subject: [PATCH 3/3] Simplify SCIP range model --- .../sourcegraph/scip_javac/ScipVisitor.java | 23 +++--- .../scip_kotlinc/ScipTextDocumentBuilder.kt | 11 ++- .../scip_kotlinc/test/ScipBuilders.kt | 11 ++- .../sourcegraph/scip/ScipDocumentBuilder.java | 8 +- .../java/com/sourcegraph/scip/ScipRange.java | 65 ++++++++++++++++ .../java/com/sourcegraph/scip/ScipRanges.java | 76 ------------------- 6 files changed, 90 insertions(+), 104 deletions(-) create mode 100644 scip-shared/src/main/java/com/sourcegraph/scip/ScipRange.java delete mode 100644 scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java diff --git a/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java b/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java index f6550e570..a6e70b12e 100644 --- a/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java +++ b/scip-javac/src/main/java/com/sourcegraph/scip_javac/ScipVisitor.java @@ -2,8 +2,7 @@ import com.sourcegraph.scip.LocalSymbolsCache; import com.sourcegraph.scip.ScipDocumentBuilder; -import com.sourcegraph.scip.ScipRanges; -import com.sourcegraph.scip.ScipRanges.Range; +import com.sourcegraph.scip.ScipRange; import com.sourcegraph.scip.ScipSymbols; import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.ClassTree; @@ -184,7 +183,7 @@ private void resolveMethodTree(MethodTree node, TreePath treePath) { private void resolveVariableTree(VariableTree node, TreePath treePath) { Element sym = trees.getElement(treePath); if (sym == null) return; - Range range = + ScipRange range = emitDefinition(sym, node, sym.getSimpleName(), CompilerRange.FROM_POINT_WITH_TEXT_SEARCH); if (sym.getKind() == ElementKind.ENUM_CONSTANT) { TreePath typeTreePath = nodes.get(node.getInitializer()); @@ -248,8 +247,8 @@ private void resolveNewClassTree(NewClassTree node, TreePath treePath) { // ======================================= // Occurrence + SymbolInformation emission // ======================================= - private Range emitDefinition(Element sym, Tree tree, Name name, CompilerRange kind) { - Range range = computeRange(tree, kind, sym, name == null ? null : name.toString()); + private ScipRange emitDefinition(Element sym, Tree tree, Name name, CompilerRange kind) { + ScipRange range = computeRange(tree, kind, sym, name == null ? null : name.toString()); if (range == null) return null; emitOccurrence(sym, range, SymbolRole.Definition_VALUE, computeEnclosingRange(tree)); declTrees.put(sym, tree); @@ -258,12 +257,12 @@ private Range emitDefinition(Element sym, Tree tree, Name name, CompilerRange ki } private void emitReference(Element sym, Tree tree, Name name, CompilerRange kind) { - Range range = computeRange(tree, kind, sym, name == null ? null : name.toString()); + ScipRange range = computeRange(tree, kind, sym, name == null ? null : name.toString()); if (range == null) return; emitOccurrence(sym, range, 0 /* reference */, null); } - private void emitOccurrence(Element sym, Range range, int role, Range enclosingRange) { + private void emitOccurrence(Element sym, ScipRange range, int role, ScipRange enclosingRange) { String symbol = scipSymbol(sym); if (symbol.isEmpty()) return; Occurrence.Builder b = Occurrence.newBuilder().setSymbol(symbol).setSymbolRoles(role); @@ -370,7 +369,7 @@ private SymbolInformation.Kind scipKind(Element sym) { // ======================================= // Source position / range computation // ======================================= - private Range computeRange(Tree tree, CompilerRange kind, Element sym, String name) { + private ScipRange computeRange(Tree tree, CompilerRange kind, Element sym, String name) { if (sym == null) return null; SourcePositions sourcePositions = trees.getSourcePositions(); int start = (int) sourcePositions.getStartPosition(compUnitTree, tree); @@ -404,7 +403,7 @@ private Range computeRange(Tree tree, CompilerRange kind, Element sym, String na return lineMapRange(start, end); } - private Range computeEnclosingRange(Tree tree) { + private ScipRange computeEnclosingRange(Tree tree) { if (tree == null) return null; TreePath path = nodes.get(tree); if (path == null) return null; @@ -423,7 +422,7 @@ private Range computeEnclosingRange(Tree tree) { return lineMapRange(start, end); } - private Range lineMapRange(int start, int end) { + private ScipRange lineMapRange(int start, int end) { if (start == Diagnostic.NOPOS || end == Diagnostic.NOPOS || end <= start) return null; LineMap lineMap = compUnitTree.getLineMap(); int startLine = (int) lineMap.getLineNumber(start) - 1; @@ -441,8 +440,8 @@ private Range lineMapRange(int start, int end) { endChar -= count * 7; } - if (startLine == endLine) return ScipRanges.singleLineRange(startLine, startChar, endChar); - return ScipRanges.range(startLine, startChar, endLine, endChar); + if (startLine == endLine) return ScipRange.singleLine(startLine, startChar, endChar); + return ScipRange.range(startLine, startChar, endLine, endChar); } // ======================================= diff --git a/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt b/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt index d26f1b390..9f2c7a542 100644 --- a/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt +++ b/scip-kotlinc/src/main/kotlin/com/sourcegraph/scip_kotlinc/ScipTextDocumentBuilder.kt @@ -1,8 +1,7 @@ package com.sourcegraph.scip_kotlinc import com.sourcegraph.scip.ScipDocumentBuilder -import com.sourcegraph.scip.ScipRanges -import com.sourcegraph.scip.ScipRanges.Range +import com.sourcegraph.scip.ScipRange import com.sourcegraph.scip.ScipShardPaths import java.nio.file.Path import java.nio.file.Paths @@ -116,19 +115,19 @@ class ScipTextDocumentBuilder( return builder.build() } - private fun range(element: KtSourceElement): Range { + private fun range(element: KtSourceElement): ScipRange { val line = lineMap.lineNumber(element) - 1 val startCol = lineMap.startCharacter(element) val endCol = lineMap.endCharacter(element) - return ScipRanges.singleLineRange(line, startCol, endCol) + return ScipRange.singleLine(line, startCol, endCol) } - private fun enclosingRange(element: KtSourceElement): Range { + private fun enclosingRange(element: KtSourceElement): ScipRange { val startLine = lineMap.lineNumber(element) - 1 val startCol = lineMap.startCharacter(element) val endLine = lineMap.lineNumberForOffset(element.endOffset) - 1 val endCol = lineMap.columnForOffset(element.endOffset) - return ScipRanges.range(startLine, startCol, endLine, endCol) + return ScipRange.range(startLine, startCol, endLine, endCol) } private fun relativePath(): String = diff --git a/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt b/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt index a91f34c22..369b71acb 100644 --- a/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt +++ b/scip-kotlinc/src/test/kotlin/com/sourcegraph/scip_kotlinc/test/ScipBuilders.kt @@ -1,7 +1,6 @@ package com.sourcegraph.scip_kotlinc.test -import com.sourcegraph.scip.ScipRanges -import com.sourcegraph.scip.ScipRanges.Range +import com.sourcegraph.scip.ScipRange import org.scip_code.scip.Occurrence import org.scip_code.scip.SymbolInformation import org.scip_code.scip.SymbolRole @@ -39,9 +38,9 @@ class ScipRangeBuilder { var endLine: Int = -1 var endCharacter: Int = 0 - internal fun toScipRange(): Range { + internal fun toScipRange(): ScipRange { val line = if (endLine < 0) startLine else endLine - return ScipRanges.range(startLine, startCharacter, line, endCharacter) + return ScipRange.range(startLine, startCharacter, line, endCharacter) } } @@ -49,8 +48,8 @@ class ScipRangeBuilder { class ScipOccurrenceBuilder { var role: Int = REFERENCE var symbol: String = "" - private var range: Range? = null - private var enclosingRange: Range? = null + private var range: ScipRange? = null + private var enclosingRange: ScipRange? = null fun range(block: ScipRangeBuilder.() -> Unit) { range = ScipRangeBuilder().apply(block).toScipRange() diff --git a/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java b/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java index 34afa54c3..15eb6bf1d 100644 --- a/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java +++ b/scip-shared/src/main/java/com/sourcegraph/scip/ScipDocumentBuilder.java @@ -20,8 +20,8 @@ */ public final class ScipDocumentBuilder { private static final Comparator OCCURRENCE_ORDER = - Comparator.comparingInt(ScipRanges::rangeStartLine) - .thenComparingInt(ScipRanges::rangeStartCharacter); + Comparator.comparingInt(o -> ScipRange.from(o).startLine()) + .thenComparingInt(o -> ScipRange.from(o).startCharacter()); private final Map occurrences = new LinkedHashMap<>(); private final Map symbols = new LinkedHashMap<>(); @@ -49,12 +49,12 @@ public Document build(String language, String relativePath, String text) { } private static final class OccurrenceKey { - private final ScipRanges.Range range; + private final ScipRange range; private final String symbol; private final int roles; OccurrenceKey(Occurrence occurrence) { - this.range = ScipRanges.range(occurrence); + this.range = ScipRange.from(occurrence); this.symbol = occurrence.getSymbol(); this.roles = occurrence.getSymbolRoles(); } diff --git a/scip-shared/src/main/java/com/sourcegraph/scip/ScipRange.java b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRange.java new file mode 100644 index 000000000..4424bf737 --- /dev/null +++ b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRange.java @@ -0,0 +1,65 @@ +package com.sourcegraph.scip; + +import org.scip_code.scip.MultiLineRange; +import org.scip_code.scip.Occurrence; +import org.scip_code.scip.SingleLineRange; + +/** A normalized source range that can be serialized to SCIP's typed range oneofs. */ +public record ScipRange(int startLine, int startCharacter, int endLine, int endCharacter) { + + public static ScipRange singleLine(int line, int startCharacter, int endCharacter) { + return new ScipRange(line, startCharacter, line, endCharacter); + } + + public static ScipRange range(int startLine, int startCharacter, int endLine, int endCharacter) { + return new ScipRange(startLine, startCharacter, endLine, endCharacter); + } + + public static ScipRange from(Occurrence occurrence) { + switch (occurrence.getTypedRangeCase()) { + case SINGLE_LINE_RANGE: + return from(occurrence.getSingleLineRange()); + case MULTI_LINE_RANGE: + return from(occurrence.getMultiLineRange()); + case TYPEDRANGE_NOT_SET: + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); + } + + private static ScipRange from(SingleLineRange range) { + return new ScipRange( + range.getLine(), range.getStartCharacter(), range.getLine(), range.getEndCharacter()); + } + + private static ScipRange from(MultiLineRange range) { + return new ScipRange( + range.getStartLine(), + range.getStartCharacter(), + range.getEndLine(), + range.getEndCharacter()); + } + + public boolean isSingleLine() { + return startLine == endLine; + } + + public SingleLineRange toSingleLineRange() { + if (!isSingleLine()) throw new IllegalStateException("expected single-line range"); + return SingleLineRange.newBuilder() + .setLine(startLine) + .setStartCharacter(startCharacter) + .setEndCharacter(endCharacter) + .build(); + } + + public MultiLineRange toMultiLineRange() { + if (isSingleLine()) throw new IllegalStateException("expected multi-line range"); + return MultiLineRange.newBuilder() + .setStartLine(startLine) + .setStartCharacter(startCharacter) + .setEndLine(endLine) + .setEndCharacter(endCharacter) + .build(); + } +} diff --git a/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java b/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java deleted file mode 100644 index 822c159a5..000000000 --- a/scip-shared/src/main/java/com/sourcegraph/scip/ScipRanges.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.sourcegraph.scip; - -import org.scip_code.scip.MultiLineRange; -import org.scip_code.scip.Occurrence; -import org.scip_code.scip.SingleLineRange; - -/** Helpers for creating and reading typed SCIP occurrence ranges. */ -public final class ScipRanges { - private ScipRanges() {} - - public static Range singleLineRange(int line, int startCharacter, int endCharacter) { - return new Range(line, startCharacter, line, endCharacter); - } - - public static Range range(int startLine, int startCharacter, int endLine, int endCharacter) { - return new Range(startLine, startCharacter, endLine, endCharacter); - } - - public static Range range(Occurrence occurrence) { - switch (occurrence.getTypedRangeCase()) { - case SINGLE_LINE_RANGE: - return Range.from(occurrence.getSingleLineRange()); - case MULTI_LINE_RANGE: - return Range.from(occurrence.getMultiLineRange()); - case TYPEDRANGE_NOT_SET: - throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); - } - throw new IllegalArgumentException("expected SCIP 0.9 typed occurrence range"); - } - - public static int rangeStartLine(Occurrence occurrence) { - return range(occurrence).startLine(); - } - - public static int rangeStartCharacter(Occurrence occurrence) { - return range(occurrence).startCharacter(); - } - - public record Range(int startLine, int startCharacter, int endLine, int endCharacter) { - private static Range from(SingleLineRange range) { - return new Range( - range.getLine(), range.getStartCharacter(), range.getLine(), range.getEndCharacter()); - } - - private static Range from(MultiLineRange range) { - return new Range( - range.getStartLine(), - range.getStartCharacter(), - range.getEndLine(), - range.getEndCharacter()); - } - - public boolean isSingleLine() { - return startLine == endLine; - } - - public SingleLineRange toSingleLineRange() { - if (!isSingleLine()) throw new IllegalStateException("expected single-line range"); - return SingleLineRange.newBuilder() - .setLine(startLine) - .setStartCharacter(startCharacter) - .setEndCharacter(endCharacter) - .build(); - } - - public MultiLineRange toMultiLineRange() { - if (isSingleLine()) throw new IllegalStateException("expected multi-line range"); - return MultiLineRange.newBuilder() - .setStartLine(startLine) - .setStartCharacter(startCharacter) - .setEndLine(endLine) - .setEndCharacter(endCharacter) - .build(); - } - } -}