Severity: low — degenerate output on inputs that current callers don't generate, but the silent failure mode is bad if a future caller emits one.
Symptom
SymbolId.fromSemanticDb treats anything not ending in # as a term:
val isType = if classPart.endsWith("#") then true else false
For SemanticDB inputs that end in / (package symbols like scala/collection/) or other unexpected sigils (e.g. [T] for type arguments), the classifier wrongly defaults to term. The parser then strips one #/. (no-op for trailing-/) and tokenises by [.#], returning empty tokens for a trailing-/ package.
fromSemanticDb("scala/collection/") → pkg=["scala","collection"], classPart="", tokens=Nil → returns SymbolId(pkg, Nil, "", None) — a term id with empty name. Map lookups by this id would collide across all such cases.
Fix
Recognise SemanticDB sentinels explicitly and return either a sentinel-discriminated id or skip outright. Sketch:
def fromSemanticDb(sdbSymbol: String): SymbolId = {
val cleaned = sdbSymbol.replaceAll("\\(\\+?\\d*\\)", "")
if cleaned.isEmpty then return SymbolId(Nil, Nil, "", None)
if cleaned.endsWith("/") then {
// Package symbol — encode the trailing segment as the name with member=None.
val pkgs = cleaned.stripSuffix("/").split('/').toList.filter(_.nonEmpty)
return pkgs match {
case Nil => SymbolId(Nil, Nil, "", None)
case many => SymbolId.tpe(many.init, Nil, many.last)
}
}
// ... rest of current implementation, but assert classPart non-empty before tokenising
}
Decide whether package symbols should round-trip through fromSemanticDb at all — they may not be a real use case for find-references. If not, log + return a sentinel instead.
Acceptance criteria
fromSemanticDb("scala/collection/") returns something non-degenerate (either tpe(["scala"], Nil, "collection") or an explicit sentinel)
- Decision documented in the factory docstring
Severity: low — degenerate output on inputs that current callers don't generate, but the silent failure mode is bad if a future caller emits one.
Symptom
SymbolId.fromSemanticDbtreats anything not ending in#as a term:For SemanticDB inputs that end in
/(package symbols likescala/collection/) or other unexpected sigils (e.g.[T]for type arguments), the classifier wrongly defaults to term. The parser then strips one#/.(no-op for trailing-/) and tokenises by[.#], returning empty tokens for a trailing-/package.fromSemanticDb("scala/collection/")→pkg=["scala","collection"],classPart="",tokens=Nil→ returnsSymbolId(pkg, Nil, "", None)— a term id with empty name. Map lookups by this id would collide across all such cases.Fix
Recognise SemanticDB sentinels explicitly and return either a sentinel-discriminated id or skip outright. Sketch:
Decide whether package symbols should round-trip through
fromSemanticDbat all — they may not be a real use case for find-references. If not, log + return a sentinel instead.Acceptance criteria
fromSemanticDb("scala/collection/")returns something non-degenerate (eithertpe(["scala"], Nil, "collection")or an explicit sentinel)