Skip to content

Commit

Permalink
fix: use alternative with stripped synthetic filename$package.
Browse files Browse the repository at this point in the history
  • Loading branch information
kasiaMarek committed Dec 3, 2024
1 parent ce50dee commit 018f323
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,10 @@ object MtagsEnrichments extends ScalametaCommonEnrichments:
def stripBackticks: String = s.stripPrefix("`").stripSuffix("`")

extension (search: SymbolSearch)
def symbolDocumentation(symbol: Symbol, contentType: ContentType = ContentType.MARKDOWN)(using
Context
): Option[SymbolDocumentation] =
def symbolDocumentation(
symbol: Symbol,
contentType: ContentType = ContentType.MARKDOWN
)(using Context): Option[SymbolDocumentation] =
def toSemanticdbSymbol(symbol: Symbol) =
SemanticdbSymbols.symbolName(
if !symbol.is(JavaDefined) && symbol.isPrimaryConstructor then
Expand Down
30 changes: 29 additions & 1 deletion mtags/src/main/scala/scala/meta/internal/metals/Docstrings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import scala.meta.pc.SymbolDocumentation
*/
class Docstrings(index: GlobalSymbolIndex) {
val cache = new TrieMap[Content, SymbolDocumentation]()
val alternativesMap = new TrieMap[String, Set[String]]
private val logger = Logger.getLogger(classOf[Docstrings].getName)

def documentation(
Expand Down Expand Up @@ -130,6 +131,7 @@ class Docstrings(index: GlobalSymbolIndex) {
case Some(defn) =>
try {
indexSymbolDefinition(defn, contentType)
maybeCacheAlternative(defn, contentType)
} catch {
case NonFatal(e) =>
logger.log(Level.SEVERE, defn.path.toURI.toString, e)
Expand All @@ -138,6 +140,29 @@ class Docstrings(index: GlobalSymbolIndex) {
}
}

private def maybeCacheAlternative(
defn: SymbolDefinition,
contentType: ContentType
) = {
val defSymbol = defn.definitionSymbol.value
val querySymbol = defn.querySymbol.value
lazy val queryContent = Content.from(querySymbol, contentType)

if (defSymbol != querySymbol && !cache.contains(queryContent)) {
cache
.get(Content.from(defSymbol, contentType))
.foreach(cache.put(queryContent, _))

alternativesMap.synchronized {
val prev = alternativesMap.get(defSymbol)
alternativesMap.put(
defSymbol,
prev.map(_ + querySymbol).getOrElse(Set(querySymbol))
)
}
}
}

private def indexSymbolDefinition(
defn: SymbolDefinition,
contentType: ContentType
Expand Down Expand Up @@ -166,7 +191,10 @@ class Docstrings(index: GlobalSymbolIndex) {
): Unit = {
for {
contentType <- ContentType.values()
} cache.remove(Content.from(occ.symbol, contentType))
symbol <- alternativesMap
.remove(occ.symbol)
.getOrElse(Set.empty) + occ.symbol
} cache.remove(Content.from(symbol, contentType))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
package scala.meta.internal.mtags

import scala.meta.internal.semanticdb.Scala._
import MtagsEnrichments._

object DefinitionAlternatives {
type ValidateLocation = SymbolLocation => Boolean

/**
* Returns a list of fallback symbols that can act instead of given symbol.
*/
def apply(symbol: Symbol): List[Symbol] = {
List(
caseClassCompanionToType(symbol),
caseClassApplyOrCopy(symbol),
caseClassApplyOrCopyParams(symbol),
initParamToValue(symbol),
varGetter(symbol),
methodOwner(symbol),
objectInsteadOfAny(symbol)
).flatten
def apply(symbol: Symbol): List[(Symbol, Option[ValidateLocation])] = {
stripSyntheticPackageObjectFromObject(symbol).toList ++
List(
caseClassCompanionToType(symbol),
caseClassApplyOrCopy(symbol),
caseClassApplyOrCopyParams(symbol),
initParamToValue(symbol),
varGetter(symbol),
methodOwner(symbol),
objectInsteadOfAny(symbol)
).flatten.map((_, None))
}

object GlobalSymbol {
Expand All @@ -26,6 +29,27 @@ object DefinitionAlternatives {
Some(sym.owner -> sym.value.desc)
}

private def stripSyntheticPackageObjectFromObject(
symbol: Symbol
): Option[(Symbol, Option[ValidateLocation])] = {
val toplevel = symbol.toplevel
Option(toplevel).flatMap {
case GlobalSymbol(owner, Descriptor.Term(pkgName))
if pkgName.endsWith("$package") =>
val newSymbol =
Symbol(s"${owner.value}${symbol.value.stripPrefix(toplevel.value)}")
if (newSymbol.toplevel.isTerm) {
Some(
(
newSymbol,
Some(loc => s"${loc.path.scalaFileName}$$package" == pkgName)
)
)
} else None
case _ => None
}
}

/**
* If `case class A(a: Int)` and there is no companion object, resolve
* `A` in `A(1)` to the class definition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ trait ScalametaCommonEnrichments extends CommonMtagsEnrichments {

def filename: String = path.toNIO.filename

def scalaFileName: String =
path.filename.stripSuffix(".scala").stripSuffix(".sc")

def toIdeallyRelativeURI(sourceItemOpt: Option[AbsolutePath]): String =
sourceItemOpt match {
case Some(sourceItem) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import scala.meta.internal.mtags.ScalametaCommonEnrichments._
import scala.meta.internal.semanticdb.Scala._
import scala.meta.internal.{semanticdb => s}
import scala.meta.io.AbsolutePath
import scala.meta.internal.mtags.DefinitionAlternatives.ValidateLocation

final case class SymbolLocation(
path: AbsolutePath,
Expand Down Expand Up @@ -190,7 +191,8 @@ class SymbolIndexBucket(
*/
private def query0(
querySymbol: Symbol,
symbol: Symbol
symbol: Symbol,
validate: Option[ValidateLocation] = None
): List[SymbolDefinition] = {

removeOldEntries(symbol)
Expand Down Expand Up @@ -224,21 +226,27 @@ class SymbolIndexBucket(
if (!definitions.contains(symbol.value)) {
// Fallback 3: guess related symbols from the enclosing class.
DefinitionAlternatives(symbol)
.flatMap(alternative => query0(querySymbol, alternative))
.flatMap { case (alternative, validate) =>
query0(querySymbol, alternative, validate)
}
} else {
definitions
.get(symbol.value)
.map { paths =>
paths.map { location =>
SymbolDefinition(
querySymbol = querySymbol,
definitionSymbol = symbol,
path = location.path,
dialect = dialect,
range = location.range,
kind = None,
properties = 0
)
paths.flatMap { location =>
if (validate.forall(_(location))) {
Some(
SymbolDefinition(
querySymbol = querySymbol,
definitionSymbol = symbol,
path = location.path,
dialect = dialect,
range = location.range,
kind = None,
properties = 0
)
)
} else None
}.toList
}
.getOrElse(List.empty)
Expand Down
16 changes: 16 additions & 0 deletions tests/cross/src/test/scala/tests/hover/HoverScala3TypeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -595,4 +595,20 @@ class HoverScala3TypeSuite extends BaseHoverSuite {
|""".stripMargin
)

check(
"i6852",
"""
|type Foo = String
|
|/** some doc */
|object Foo:
| /** doc doc */
| val fo@@o = ""
|""".stripMargin,
"""|```scala
|val foo: String
|```
|doc doc""".stripMargin
)

}

0 comments on commit 018f323

Please sign in to comment.