Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement: if no binary version in jar path try using build target info #6698

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ final class ImplementationProvider(
}

private def semanticdbForJarFile(fileSource: AbsolutePath) = {
val dialect = ScalaVersions.dialectForDependencyJar(fileSource.filename)
val dialect =
ScalaVersions.dialectForDependencyJar(fileSource, buildTargets)
FileIO.slurp(fileSource, StandardCharsets.UTF_8)
val textDocument = Mtags.index(fileSource, dialect)
textDocument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,14 @@ final class BuildTargets private (
* @return path to the source jar for that jar
*/
private def sourceJarPathFallback(
sourceJarPath: AbsolutePath
sourceJarPath: AbsolutePath,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would probably need to rename the parameters and the method

inputIsSourceJar: Boolean = false,
): Option[AbsolutePath] = {
val (from, to) =
if (inputIsSourceJar) ("-sources.jar", ".jar")
else (".jar", "-sources.jar")
val fallback = sourceJarPath.parent.resolve(
sourceJarPath.filename.replace(".jar", "-sources.jar")
sourceJarPath.filename.replace(from, to)
)
if (fallback.exists) Some(fallback)
else None
Expand Down Expand Up @@ -578,18 +582,29 @@ final class BuildTargets private (
jar: AbsolutePath,
): Option[AbsolutePath] = {
data
.fromOptions(_.findSourceJarOf(jar, Some(id)))
.fromOptions(_.findConnectedArtifact(jar, Some(id)))
.orElse(sourceJarPathFallback(jar))
}

def sourceJarFor(
jar: AbsolutePath
): Option[AbsolutePath] = {
data
.fromOptions(_.findSourceJarOf(jar, targetId = None))
.fromOptions(_.findConnectedArtifact(jar, targetId = None))
.orElse(sourceJarPathFallback(jar))
}

def findJarFor(
id: BuildTargetIdentifier,
sourceJar: AbsolutePath,
): Option[AbsolutePath] = {
data
.fromOptions(
_.findConnectedArtifact(sourceJar, Some(id), classifier = null)
)
.orElse(sourceJarPathFallback(sourceJar, inputIsSourceJar = true))
}

def inverseDependencySource(
sourceJar: AbsolutePath
): collection.Set[BuildTargetIdentifier] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ case class Indexer(indexProviders: IndexProviders)(implicit rc: ReportContext) {
case Right(zip) =>
scribe.debug(s"Indexing JDK sources from $zip")
usedJars += zip
val dialect = ScalaVersions.dialectForDependencyJar(zip.filename)
val dialect = ScalaVersions.dialectForDependencyJar(zip, buildTargets)
sharedIndices.jvmTypeHierarchy.getTypeHierarchy(zip) match {
case Some(overrides) =>
definitionIndex.addIndexedSourceJar(zip, Nil, dialect)
Expand Down Expand Up @@ -540,7 +540,7 @@ case class Indexer(indexProviders: IndexProviders)(implicit rc: ReportContext) {
* @param path JAR path
*/
private def addSourceJarSymbols(path: AbsolutePath): Unit = {
val dialect = ScalaVersions.dialectForDependencyJar(path.filename)
val dialect = ScalaVersions.dialectForDependencyJar(path, buildTargets)
tables.jarSymbols.getTopLevels(path) match {
case Some(toplevels) =>
tables.jarSymbols.getTypeHierarchy(path) match {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package scala.meta.internal.metals

import java.io.UncheckedIOException

import scala.collection.concurrent.TrieMap

import scala.meta.Dialect
import scala.meta.dialects._
import scala.meta.internal.io.FileIO
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.semver.SemVer
import scala.meta.io.AbsolutePath

class ScalaVersions(
deprecatedScalaVersions: Seq[String],
Expand All @@ -13,6 +20,8 @@ class ScalaVersions(
scala3: String,
) {

private val jarScalaVersionIndex = TrieMap[String, String]()

def isScala3Milestone(version: String): Boolean =
version.startsWith("3.0.0-M") || version.startsWith("3.0.0-RC")

Expand Down Expand Up @@ -147,7 +156,9 @@ class ScalaVersions(
}

private val scalaVersionRegex =
raw"(_)(\d)(\.\d{1,2})?(\.\d(-(RC|M)\d)?)?".r
raw"_(\d)(\.\d{1,2})?(\.\d(-(RC|M)\d)?)?".r
private val scalaLibraryRegex =
raw"scala-library-(\d)(\.\d{1,2})(\.\d(-(RC|M)\d)?)".r

/**
* Extract scala binary version from dependency jar name.
Expand All @@ -157,35 +168,66 @@ class ScalaVersions(
* `some-library_2.13-4.5.0` -> 2.13
* `some-library_2.13-2.11` -> 2.13
*/
def scalaBinaryVersionFromJarName(filename: String): String = {
def scalaBinaryVersionFromJarName(filename: String): Option[String] = {
val dropEnding = filename
.stripSuffix(".jar")

scalaVersionRegex
.findAllMatchIn(dropEnding)
.toList
List(scalaLibraryRegex, scalaVersionRegex)
.flatMap(_.findAllMatchIn(dropEnding).toList)
.flatMap { m =>
val hasUnderscorePrefix = Option(m.group(1)).isDefined
val major = m.group(2)
val minor = Option(m.group(3)).getOrElse("")
val ending = Option(m.group(4)).getOrElse("")
val major = m.group(1)
val minor = Option(m.group(2)).getOrElse("")
val ending = Option(m.group(3)).getOrElse("")
val version = s"$major$minor$ending"

if (isSupportedScalaBinaryVersion(version))
Some(version -> hasUnderscorePrefix)
Some(version)
else None
}
.sortBy(_._2)(Ordering.Boolean.reverse)
.headOption
.map { case (version, _) => scalaBinaryVersionFromFullVersion(version) }
.getOrElse("2.13")
.map(scalaBinaryVersionFromFullVersion)
}

def dialectForDependencyJar(filename: String): Dialect =
dialectForScalaVersion(
scalaBinaryVersionFromJarName(filename),
includeSource3 = true,
)
def dialectForDependencyJar(
jar: AbsolutePath,
buildTargets: BuildTargets,
): Dialect = {
lazy val buildTargetAndScalaVersion =
buildTargets
.inverseDependencySource(jar)
.flatMap(id => buildTargets.scalaTarget(id))
.map(target => (target.scalaBinaryVersion, target.id))
.toList
.sortBy(_._1)
.headOption

def fromTastyExistance = {
val fromTasty = buildTargetAndScalaVersion
.flatMap { case (_, id) => buildTargets.findJarFor(id, jar) }
.flatMap(
FileIO.withJarFileSystem(_, create = false) { root =>
try {
root.listRecursive
.find(f => f.isFile && f.filename.endsWith(".tasty"))
.map(_ => "3")
.orElse(Some("2.13"))
} catch {
case _: UncheckedIOException => None
}
}
)
fromTasty.foreach(jarScalaVersionIndex.put(jar.toURI.toString(), _))
fromTasty
}

val scalaVersion =
scalaBinaryVersionFromJarName(jar.toNIO.getFileName().toString())
.orElse(jarScalaVersionIndex.get(jar.toURI.toString()))
.orElse(fromTastyExistance)
.orElse(buildTargetAndScalaVersion.map(_._1))
.getOrElse("2.13")
dialectForScalaVersion(scalaVersion, includeSource3 = true)
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ class StandaloneSymbolSearch(

private val index = OnDemandSymbolIndex.empty()
sources.foreach(s =>
index.addSourceJar(s, ScalaVersions.dialectForDependencyJar(s.filename))
index.addSourceJar(
s,
ScalaVersions.dialectForDependencyJar(s, buildTargets),
)
)

private val docs = new Docstrings(index)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,10 @@ final class TargetData {
}
}

def findSourceJarOf(
def findConnectedArtifact(
jar: AbsolutePath,
targetId: Option[BuildTargetIdentifier],
classifier: String = "sources",
): Option[AbsolutePath] = {
val jarUri = jar.toURI.toString()
def depModules: Iterator[MavenDependencyModule] = targetId match {
Expand All @@ -228,10 +229,10 @@ final class TargetData {
module <- depModules
artifacts = module.getArtifacts().asScala
if artifacts.exists(artifact => isUriEqual(artifact.getUri(), jarUri))
sourceJar <- artifacts.find(_.getClassifier() == "sources")
sourceJarPath = sourceJar.getUri().toAbsolutePath
if sourceJarPath.exists
} yield sourceJarPath
foundJar <- artifacts.find(_.getClassifier() == classifier)
foundJarPath = foundJar.getUri().toAbsolutePath
if foundJarPath.exists
} yield foundJarPath
allFound.headOption
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,8 @@ class MetalsTreeViewProvider(
val dialect =
if (path.isJarFileSystem) {
path.jarPath
.map { p =>
ScalaVersions.dialectForDependencyJar(p.filename)
}
.flatMap(p => ScalaVersions.scalaBinaryVersionFromJarName(p.filename))
.map(ScalaVersions.dialectForScalaVersion(_, includeSource3 = true))
.getOrElse(dialects.Scala3)
} else dialectFromWorkspace
val input = path.toInput
Expand Down Expand Up @@ -264,7 +263,7 @@ class FolderTreeViewProvider(
valueTooltip = _.toString,
toplevels = () => buildTargets.allSourceJars.filter(_.exists),
loadSymbols = (path, symbol) => {
val dialect = ScalaVersions.dialectForDependencyJar(path.filename)
val dialect = ScalaVersions.dialectForDependencyJar(path, buildTargets)
classpath.jarSymbols(path, symbol, dialect)
},
toplevelIcon = "package",
Expand Down
6 changes: 5 additions & 1 deletion tests/unit/src/main/scala/tests/MetalsTestEnrichments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ object MetalsTestEnrichments {
}
libraries.foreach(
_.sources.entries.foreach { s =>
val dialect = ScalaVersions.dialectForDependencyJar(s.filename)
val version = ScalaVersions
.scalaBinaryVersionFromJarName(s.filename)
.getOrElse("2.13")
val dialect =
ScalaVersions.dialectForScalaVersion(version, includeSource3 = true)
wsp.index.addSourceJar(s, dialect)
}
)
Expand Down
8 changes: 7 additions & 1 deletion tests/unit/src/test/scala/tests/DefinitionSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,15 @@ abstract class DefinitionSuiteBase(
// Step 2. Index dependency sources
index.addSourceJar(JdkSources().right.get, dialect)
input.dependencySources.entries.foreach { jar =>
val scalaVersion = ScalaVersions
.scalaBinaryVersionFromJarName(jar.filename)
.getOrElse("2.13")
index.addSourceJar(
jar,
ScalaVersions.dialectForDependencyJar(jar.filename),
ScalaVersions.dialectForScalaVersion(
scalaVersion,
includeSource3 = true,
),
)
}

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/src/test/scala/tests/ScalaVersionsSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ class ScalaVersionsSuite extends BaseSuite {
checkJar("tested-3.0-sources.jar", "2.13")

def checkJar(jar: String, expected: String): Unit = test(jar) {
val out = ScalaVersions.scalaBinaryVersionFromJarName(jar)
val out = ScalaVersions.scalaBinaryVersionFromJarName(jar).getOrElse("2.13")
assertEquals(out, expected, jar)
}

Expand Down
Loading