Skip to content

Commit

Permalink
bugfix: handle nested java jars
Browse files Browse the repository at this point in the history
  • Loading branch information
kasiaMarek committed Feb 5, 2024
1 parent 3204a2f commit 95c6a05
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ class JavaToplevelMtags(val input: Input.VirtualFile) extends MtagsIndexer {
}
}

def readPackage: List[String] = {
fetchToken // start of file
fetchToken match {
case Token.Package => readPaths.map(_.value)
case _ => Nil
}
}

private def loop: Unit = {
val token = fetchToken
token match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import scala.util.control.NonFatal
import scala.meta.Dialect
import scala.meta.internal.io.FileIO
import scala.meta.internal.io.PathIO
import scala.meta.internal.mtags.JavaToplevelMtags
import scala.meta.internal.mtags.ScalametaCommonEnrichments._
import scala.meta.internal.semanticdb.Scala._
import scala.meta.internal.{semanticdb => s}
Expand Down Expand Up @@ -65,6 +66,8 @@ class SymbolIndexBucket(
root.listRecursive.toList.flatMap {
case source if source.isScala =>
addSourceFile(source, None).map(sym => (sym, source))
case source if source.isJava =>
addJavaSourceFile(source).map(sym => (sym, source))
case _ =>
List.empty
}
Expand All @@ -91,6 +94,33 @@ class SymbolIndexBucket(
}
}

/* Sometimes source jars have additional nested directories,
* in that case java toplevel is not "trivial".
* See: https://github.com/scalameta/metals/issues/3815
*/
def addJavaSourceFile(source: AbsolutePath): List[String] = {
new JavaToplevelMtags(source.toInput).readPackage match {
case Nil => Nil
case packageParts =>
val className = source.filename.stripSuffix(".java")
val symbol = packageParts.mkString("", "/", s"/$className#")
if (
isTrivialToplevelSymbol(
source.toURI.toString,
symbol,
extension = "java"
)
) Nil
else {
toplevels.updateWith(symbol) {
case Some(acc) => Some(acc + source)
case None => Some(Set(source))
}
List(symbol)
}
}
}

def addSourceFile(
source: AbsolutePath,
sourceDirectory: Option[AbsolutePath]
Expand Down Expand Up @@ -121,9 +151,13 @@ class SymbolIndexBucket(
// Returns true if symbol is com/foo/Bar# and path is /com/foo/Bar.scala
// Such symbols are "trivial" because their definition location can be computed
// on the fly.
private def isTrivialToplevelSymbol(path: String, symbol: String): Boolean = {
private def isTrivialToplevelSymbol(
path: String,
symbol: String,
extension: String = "scala"
): Boolean = {
val pathBuffer =
CharBuffer.wrap(path).subSequence(1, path.length - ".scala".length)
CharBuffer.wrap(path).subSequence(1, path.length - extension.length - 1)
val symbolBuffer =
CharBuffer.wrap(symbol).subSequence(0, symbol.length - 1)
pathBuffer.equals(symbolBuffer)
Expand Down
38 changes: 38 additions & 0 deletions tests/unit/src/test/scala/tests/DefinitionLspSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -714,4 +714,42 @@ class DefinitionLspSuite
} yield ()
}

test("nested-jars") {
cleanWorkspace()
for {
_ <- initialize(
s"""
|/metals.json
|{
| "a": {
| "libraryDependencies": [
| "com.daml:bindings-rxjava:2.0.0"
| ]
| }
|}
|/a/src/main/scala/a/Main.scala
|package a
|import com.daml.ledger.rxjava.DamlLedgerClient
|
|object O {
| val k: DamlLedgerClient = ???
|}
|""".stripMargin
)
_ <- server.didOpen("a/src/main/scala/a/Main.scala")
_ = assertNoDiagnostics()
_ = assertNoDiff(
server.workspaceDefinitions,
"""|/a/src/main/scala/a/Main.scala
|package a
|import com.daml.ledger.rxjava.DamlLedgerClient/*DamlLedgerClient.java*/
|
|object O/*L3*/ {
| val k/*L4*/: DamlLedgerClient/*DamlLedgerClient.java*/ = ???/*Predef.scala*/
|}
|""".stripMargin,
)
} yield ()
}

}

0 comments on commit 95c6a05

Please sign in to comment.