Skip to content

fix: go to def should lead to all: apply, object and class #22771

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

Merged
merged 1 commit into from
Mar 14, 2025
Merged
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 @@ -100,9 +100,9 @@ object MetalsInteractive:
pos: SourcePosition,
indexed: IndexedContext,
skipCheckOnName: Boolean = false
): List[Symbol] =
)(using Context): List[Symbol] =
enclosingSymbolsWithExpressionType(path, pos, indexed, skipCheckOnName)
.map(_._1)
.map(_._1.sourceSymbol)

/**
* Returns the list of tuple enclosing symbol and
Expand Down Expand Up @@ -217,6 +217,15 @@ object MetalsInteractive:
val tpe = getIndex(t2).getOrElse(NoType)
List((ddef.symbol, tpe, Some(name)))

case head :: (sel @ Select(_, name)) :: _
if head.sourcePos.encloses(sel.sourcePos) && (name == StdNames.nme.apply || name == StdNames.nme.unapply) =>
val optObjectSymbol = List(head.symbol).filter(sym => !(sym.is(Synthetic) && sym.is(Module)))
val classSymbol = head.symbol.companionClass
val optApplySymbol = List(sel.symbol).filter(sym => !sym.is(Synthetic))
val symbols = optObjectSymbol ++ (classSymbol :: optApplySymbol)
symbols.collect:
case sym if sym.exists => (sym, sym.info, None)

case path @ head :: tail =>
if head.symbol.is(Exported) then
val sym = head.symbol.sourceSymbol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class PcDefinitionProvider(
.untypedPath(pos.span)
.collect { case t: untpd.Tree => t }

definitionsForSymbol(untpdPath.headOption.map(_.symbol).toList, uri, pos)
definitionsForSymbols(untpdPath.headOption.map(_.symbol).toList, uri, pos)
end fallbackToUntyped

private def findDefinitions(
Expand All @@ -89,7 +89,7 @@ class PcDefinitionProvider(
uri: URI,
): DefinitionResult =
import indexed.ctx
definitionsForSymbol(
definitionsForSymbols(
MetalsInteractive.enclosingSymbols(path, pos, indexed),
uri,
pos
Expand All @@ -113,68 +113,58 @@ class PcDefinitionProvider(
case Nil =>
path.headOption match
case Some(value: Literal) =>
definitionsForSymbol(List(value.typeOpt.widen.typeSymbol), uri, pos)
definitionsForSymbols(List(value.typeOpt.widen.typeSymbol), uri, pos)
case _ => DefinitionResultImpl.empty
case _ =>
definitionsForSymbol(typeSymbols, uri, pos)

definitionsForSymbols(typeSymbols, uri, pos)
end findTypeDefinitions

private def definitionsForSymbol(
private def definitionsForSymbols(
symbols: List[Symbol],
uri: URI,
pos: SourcePosition
)(using ctx: Context): DefinitionResult =
symbols match
case symbols @ (sym :: other) =>
val isLocal = sym.source == pos.source
if isLocal then
val include = Include.definitions | Include.local
val (exportedDefs, otherDefs) =
Interactive.findTreesMatching(driver.openedTrees(uri), include, sym)
.partition(_.tree.symbol.is(Exported))

otherDefs.headOption.orElse(exportedDefs.headOption) match
case Some(srcTree) =>
val pos = srcTree.namePos
if pos.exists then
val loc = new Location(params.uri().toString(), pos.toLsp)
DefinitionResultImpl(
SemanticdbSymbols.symbolName(sym),
List(loc).asJava,
)
else DefinitionResultImpl.empty
case None =>
DefinitionResultImpl.empty
else
val res = new ArrayList[Location]()
semanticSymbolsSorted(symbols)
.foreach { sym =>
res.addAll(search.definition(sym, params.uri()))
}
DefinitionResultImpl(
SemanticdbSymbols.symbolName(sym),
res
)
end if
semanticSymbolsSorted(symbols) match
case Nil => DefinitionResultImpl.empty
end match
end definitionsForSymbol
case syms @ ((_, headSym) :: tail) =>
val locations = syms.flatMap:
case (sym, semanticdbSymbol) =>
locationsForSymbol(sym, semanticdbSymbol, uri, pos)
DefinitionResultImpl(headSym, locations.asJava)

private def locationsForSymbol(
symbol: Symbol,
semanticdbSymbol: String,
uri: URI,
pos: SourcePosition
)(using ctx: Context): List[Location] =
val isLocal = symbol.source == pos.source
if isLocal then
val trees = driver.openedTrees(uri)
val include = Include.definitions | Include.local
val (exportedDefs, otherDefs) =
Interactive.findTreesMatching(trees, include, symbol)
.partition(_.tree.symbol.is(Exported))
otherDefs.headOption.orElse(exportedDefs.headOption).collect:
case srcTree if srcTree.namePos.exists =>
new Location(params.uri().toString(), srcTree.namePos.toLsp)
.toList
else search.definition(semanticdbSymbol, uri).asScala.toList

def semanticSymbolsSorted(
syms: List[Symbol]
)(using ctx: Context): List[String] =
)(using ctx: Context): List[(Symbol, String)] =
syms
.map { sym =>
.collect { case sym if sym.exists =>
// in case of having the same type and teerm symbol
// term comes first
// used only for ordering symbols that come from `Import`
val termFlag =
if sym.is(ModuleClass) then sym.sourceModule.isTerm
else sym.isTerm
(termFlag, SemanticdbSymbols.symbolName(sym))
(termFlag, sym.sourceSymbol, SemanticdbSymbols.symbolName(sym))
}
.sorted
.map(_._2)
.sortBy { case (termFlag, _, name) => (termFlag, name) }
.map(_.tail)

end PcDefinitionProvider
Original file line number Diff line number Diff line change
Expand Up @@ -512,3 +512,75 @@ class PcDefinitionSuite extends BasePcDefinitionSuite:
|val foo_name = foo.na@@me
|""".stripMargin
)

@Test def `object` =
check(
"""|package a
|object <<Bar>> {
| def foo = 42
|}
|val m = B@@ar.foo
|""".stripMargin
)

@Test def i7267 =
check(
"""|package a
|trait Foo {
| def someNum: Int
| def <<apply>>(i: Int): Unit = println(someNum)
|}
|object <<Bar>> extends Foo {
| def someNum = 42
|}
|
|object Test {
| B@@ar(2)
|}
|""".stripMargin
)

@Test def `i7267-2` =
check(
"""|package b
|trait Foo {
| def someNum: Int
| def <<unapply>>(i: Int): Option[Int] = Some(i)
|}
|object <<Bar>> extends Foo {
| def someNum = 42
|}
|
|object Test {
| Bar.someNum match {
| case B@@ar(1) => ???
| case _ =>
| }
|}
|""".stripMargin
)

@Test def `i7267-3` =
check(
"""|package c
|case class <<Bar>>()
|object <<Bar>>
|object O {
| val a = B@@ar()
|}
|""".stripMargin
)

@Test def `i7267-4` =
check(
"""|package d
|class <<Bar>>()
|object <<Bar>> {
| def <<apply>>(): Bar = new Bar()
|}
|object O {
| val a = B@@ar()
|}
|""".stripMargin
)

Loading