Skip to content

Commit

Permalink
refactor: Move scala 3 library patching to mtags
Browse files Browse the repository at this point in the history
  • Loading branch information
tgodzik committed Nov 3, 2023
1 parent 5f42d60 commit c758243
Show file tree
Hide file tree
Showing 18 changed files with 162 additions and 178 deletions.
20 changes: 17 additions & 3 deletions metals-bench/src/main/scala/bench/MetalsBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import scala.meta.dialects
import scala.meta.interactive.InteractiveSemanticdb
import scala.meta.internal.metals.EmptyReportContext
import scala.meta.internal.metals.JdkSources
import scala.meta.internal.metals.ReportContext
import scala.meta.internal.metals.logging.MetalsLogger
import scala.meta.internal.mtags.JavaMtags
import scala.meta.internal.mtags.Mtags
import scala.meta.internal.mtags.OnDemandSymbolIndex
import scala.meta.internal.mtags.ScalaMtags
import scala.meta.internal.mtags.ScalaToplevelMtags
import scala.meta.internal.mtags.SemanticdbClasspath
import scala.meta.internal.parsing.Trees
import scala.meta.internal.semanticdb.TextDocument
Expand Down Expand Up @@ -77,14 +81,22 @@ class MetalsBench {
@BenchmarkMode(Array(Mode.SingleShotTime))
def mtagsScalaIndex(): Unit = {
scalaDependencySources.inputs.foreach { input =>
Mtags.index(input, dialects.Scala213)
ScalaMtags.index(input, dialects.Scala213).index()
}
}

@Benchmark
@BenchmarkMode(Array(Mode.SingleShotTime))
def toplevelsScalaIndex(): Unit = {
scalaDependencySources.inputs.foreach { input => Mtags.toplevels(input) }
scalaDependencySources.inputs.foreach { input =>
implicit val rc: ReportContext = EmptyReportContext
new ScalaToplevelMtags(
input,
includeInnerClasses = false,
includeMembers = false,
dialects.Scala213,
).index()
}
}

@Benchmark
Expand Down Expand Up @@ -147,7 +159,9 @@ class MetalsBench {
@BenchmarkMode(Array(Mode.SingleShotTime))
def mtagsJavaParse(): Unit = {
javaDependencySources.inputs.foreach { input =>
Mtags.index(input, dialects.Scala213)
JavaMtags
.index(input, includeMembers = true)
.index()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,12 @@ class DestinationProvider(
private def bestTextDocument(
symbolDefinition: SymbolDefinition
): TextDocument = {
val defnRevisedInput = symbolDefinition.path.toInput
// Read text file from disk instead of editor buffers because the file
// on disk is more likely to parse.
lazy val parsed = {
mtags.index(
symbolDefinition.path.toLanguage,
defnRevisedInput,
symbolDefinition.path,
symbolDefinition.dialect,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class MetalsSymbolSearch(
} else {
dependencySourceCache.getOrElseUpdate(
path,
Mtags.topLevelSymbols(input).asJava,
Mtags.topLevelSymbols(path).asJava,
)
}
})
Expand Down
136 changes: 65 additions & 71 deletions metals/src/main/scala/scala/meta/internal/metals/PackageProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -656,81 +656,75 @@ class PackageProvider(
): List[TopLevelDeclaration] = {
val filename = path.filename
val filenamePart = filename.stripSuffix(".scala").stripSuffix(".sc")
val result = for {
content <- path.content()
} yield {
val input = Input.VirtualFile(filename, content)

def isPackageObjectLike(symbol: String) =
Set("package", filenamePart ++ "$package").contains(symbol)
def isTopLevelPackageOrPackageObject(symbol: String): Boolean =
symbol.isPackage || {
val (desc, owner) = DescriptorParser(symbol)
(isPackageObjectLike(desc.name.value)
&& isTopLevelPackageOrPackageObject(owner))
}

def alternatives(si: s.SymbolInformation): Set[String] =
if (si.isCase) Set(s"${si.symbol.dropRight(1)}.") else Set.empty

val dialect = {
val optDialect =
for {
buidTargetId <- buildTargets.inverseSources(path.value)
scalaTarget <- buildTargets.scalaTarget(buidTargetId)
} yield ScalaVersions.dialectForScalaVersion(
scalaTarget.scalaVersion,
includeSource3 = true,
)
optDialect.getOrElse(dialects.Scala213)
def isPackageObjectLike(symbol: String) =
Set("package", filenamePart ++ "$package").contains(symbol)
def isTopLevelPackageOrPackageObject(symbol: String): Boolean =
symbol.isPackage || {
val (desc, owner) = DescriptorParser(symbol)
(isPackageObjectLike(desc.name.value)
&& isTopLevelPackageOrPackageObject(owner))
}
m.internal.mtags.Mtags
.index(input, dialect)
.symbols
.flatMap { si =>
if (si.symbol.isPackage)
None
else {
val (desc, owner) = DescriptorParser(si.symbol)
val descName = desc.name.value
if (
isTopLevelPackageOrPackageObject(owner) && !isPackageObjectLike(
descName
)
) {
val packageParts =
owner
.split('/')
.filter {
case "" => false
case ObjectSymbol(obj) => !isPackageObjectLike(obj)
case _ => true
}
.drop(topLevelPackageParts.length)
.toList
Some(
TopLevelDeclaration(
descName,
packageParts,
si.isGiven || si.isExtension,
alternatives(si) + si.symbol,
)

def alternatives(si: s.SymbolInformation): Set[String] =
if (si.isCase) Set(s"${si.symbol.dropRight(1)}.") else Set.empty

val dialect = {
val optDialect =
for {
buidTargetId <- buildTargets.inverseSources(path.value)
scalaTarget <- buildTargets.scalaTarget(buidTargetId)
} yield ScalaVersions.dialectForScalaVersion(
scalaTarget.scalaVersion,
includeSource3 = true,
)
optDialect.getOrElse(dialects.Scala213)
}
m.internal.mtags.Mtags
.index(path.value, dialect)
.symbols
.flatMap { si =>
if (si.symbol.isPackage)
None
else {
val (desc, owner) = DescriptorParser(si.symbol)
val descName = desc.name.value
if (
isTopLevelPackageOrPackageObject(owner) && !isPackageObjectLike(
descName
)
) {
val packageParts =
owner
.split('/')
.filter {
case "" => false
case ObjectSymbol(obj) => !isPackageObjectLike(obj)
case _ => true
}
.drop(topLevelPackageParts.length)
.toList
Some(
TopLevelDeclaration(
descName,
packageParts,
si.isGiven || si.isExtension,
alternatives(si) + si.symbol,
)
} else None
}
}
.groupBy(decl => (decl.name, decl.innerPackageParts))
.collect { case ((name, innerPackageParts), otherDecl) =>
TopLevelDeclaration(
name,
innerPackageParts,
otherDecl.map(_.isGivenOrExtension).reduce(_ || _),
otherDecl.flatMap(_.symbols).toSet,
)
)
} else None
}
.toList
}
result.getOrElse(List.empty)
}
.groupBy(decl => (decl.name, decl.innerPackageParts))
.collect { case ((name, innerPackageParts), otherDecl) =>
TopLevelDeclaration(
name,
innerPackageParts,
otherDecl.map(_.isGivenOrExtension).reduce(_ || _),
otherDecl.flatMap(_.symbols).toSet,
)
}
.toList
}

private def extendPositionToIncludeNewLine(pos: inputs.Position) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,9 @@ class StandaloneSymbolSearch(
destinationProvider
.definition(sym, sourcePath)
.map { symDef =>
val input = symDef.path.toInput
dependencySourceCache.getOrElseUpdate(
symDef.path,
mtags.topLevelSymbols(input).asJava,
mtags.topLevelSymbols(symDef.path).asJava,
)
}
.orElse(workspaceFallback.map(_.definitionSourceToplevels(sym, source)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class IndexedSymbols(isStatisticsEnabled: Boolean)(implicit rc: ReportContext)
try {
root.listRecursive.toList.collect {
case source if source.isFile =>
(source, mtags.toplevels(source.toInput, dialect).symbols)
(source, mtags.toplevels(source, dialect).symbols)
}
} catch {
// this happens in broken jars since file from FileWalker should exists
Expand All @@ -255,7 +255,7 @@ class IndexedSymbols(isStatisticsEnabled: Boolean)(implicit rc: ReportContext)
val pathSymbolInfos = if (path.isSourcesJar) {
indexJar(path)
} else {
List((path, mtags.toplevels(path.toInput, dialect).symbols))
List((path, mtags.toplevels(path, dialect).symbols))
}
pathSymbolInfos.collect { case (path, infos) =>
infos.map { info =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ class FolderTreeViewProvider(
closestSymbol: SymbolOccurrence,
): Option[List[String]] = {
if (path.isDependencySource(folder.path) || path.isJarFileSystem) {
val closestToplevel = Symbol(closestSymbol.symbol).toplevel
def pathJar = AbsolutePath(
Paths.get(path.toNIO.getFileSystem().toString())
).dealias
Expand All @@ -414,11 +415,11 @@ class FolderTreeViewProvider(
case sources
if sources == pathJar || !path.isJarFileSystem &&
path.isSrcZipInReadonlyDirectory(folder.path) =>
libraries.toUri(sources, closestSymbol.symbol).parentChain
libraries.toUri(sources, closestToplevel.value).parentChain
}

val result = buildTargets
.inferBuildTarget(List(Symbol(closestSymbol.symbol).toplevel))
.inferBuildTarget(List(closestToplevel))
.map { inferred =>
val sourceJar = inferred.jar.parent.resolve(
inferred.jar.filename.replace(".jar", "-sources.jar")
Expand Down
Loading

0 comments on commit c758243

Please sign in to comment.