Skip to content

Commit 43c31b0

Browse files
authored
fix: go to def should lead to all: apply, object and class (#22771)
fixes: http://github.com/scalameta/metals/issues/7267
2 parents 729d743 + 6785da2 commit 43c31b0

File tree

3 files changed

+118
-47
lines changed

3 files changed

+118
-47
lines changed

presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala

+11-2
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ object MetalsInteractive:
100100
pos: SourcePosition,
101101
indexed: IndexedContext,
102102
skipCheckOnName: Boolean = false
103-
): List[Symbol] =
103+
)(using Context): List[Symbol] =
104104
enclosingSymbolsWithExpressionType(path, pos, indexed, skipCheckOnName)
105-
.map(_._1)
105+
.map(_._1.sourceSymbol)
106106

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

220+
case head :: (sel @ Select(_, name)) :: _
221+
if head.sourcePos.encloses(sel.sourcePos) && (name == StdNames.nme.apply || name == StdNames.nme.unapply) =>
222+
val optObjectSymbol = List(head.symbol).filter(sym => !(sym.is(Synthetic) && sym.is(Module)))
223+
val classSymbol = head.symbol.companionClass
224+
val optApplySymbol = List(sel.symbol).filter(sym => !sym.is(Synthetic))
225+
val symbols = optObjectSymbol ++ (classSymbol :: optApplySymbol)
226+
symbols.collect:
227+
case sym if sym.exists => (sym, sym.info, None)
228+
220229
case path @ head :: tail =>
221230
if head.symbol.is(Exported) then
222231
val sym = head.symbol.sourceSymbol

presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala

+35-45
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class PcDefinitionProvider(
7979
.untypedPath(pos.span)
8080
.collect { case t: untpd.Tree => t }
8181

82-
definitionsForSymbol(untpdPath.headOption.map(_.symbol).toList, uri, pos)
82+
definitionsForSymbols(untpdPath.headOption.map(_.symbol).toList, uri, pos)
8383
end fallbackToUntyped
8484

8585
private def findDefinitions(
@@ -89,7 +89,7 @@ class PcDefinitionProvider(
8989
uri: URI,
9090
): DefinitionResult =
9191
import indexed.ctx
92-
definitionsForSymbol(
92+
definitionsForSymbols(
9393
MetalsInteractive.enclosingSymbols(path, pos, indexed),
9494
uri,
9595
pos
@@ -113,68 +113,58 @@ class PcDefinitionProvider(
113113
case Nil =>
114114
path.headOption match
115115
case Some(value: Literal) =>
116-
definitionsForSymbol(List(value.typeOpt.widen.typeSymbol), uri, pos)
116+
definitionsForSymbols(List(value.typeOpt.widen.typeSymbol), uri, pos)
117117
case _ => DefinitionResultImpl.empty
118118
case _ =>
119-
definitionsForSymbol(typeSymbols, uri, pos)
120-
119+
definitionsForSymbols(typeSymbols, uri, pos)
121120
end findTypeDefinitions
122121

123-
private def definitionsForSymbol(
122+
private def definitionsForSymbols(
124123
symbols: List[Symbol],
125124
uri: URI,
126125
pos: SourcePosition
127126
)(using ctx: Context): DefinitionResult =
128-
symbols match
129-
case symbols @ (sym :: other) =>
130-
val isLocal = sym.source == pos.source
131-
if isLocal then
132-
val include = Include.definitions | Include.local
133-
val (exportedDefs, otherDefs) =
134-
Interactive.findTreesMatching(driver.openedTrees(uri), include, sym)
135-
.partition(_.tree.symbol.is(Exported))
136-
137-
otherDefs.headOption.orElse(exportedDefs.headOption) match
138-
case Some(srcTree) =>
139-
val pos = srcTree.namePos
140-
if pos.exists then
141-
val loc = new Location(params.uri().toString(), pos.toLsp)
142-
DefinitionResultImpl(
143-
SemanticdbSymbols.symbolName(sym),
144-
List(loc).asJava,
145-
)
146-
else DefinitionResultImpl.empty
147-
case None =>
148-
DefinitionResultImpl.empty
149-
else
150-
val res = new ArrayList[Location]()
151-
semanticSymbolsSorted(symbols)
152-
.foreach { sym =>
153-
res.addAll(search.definition(sym, params.uri()))
154-
}
155-
DefinitionResultImpl(
156-
SemanticdbSymbols.symbolName(sym),
157-
res
158-
)
159-
end if
127+
semanticSymbolsSorted(symbols) match
160128
case Nil => DefinitionResultImpl.empty
161-
end match
162-
end definitionsForSymbol
129+
case syms @ ((_, headSym) :: tail) =>
130+
val locations = syms.flatMap:
131+
case (sym, semanticdbSymbol) =>
132+
locationsForSymbol(sym, semanticdbSymbol, uri, pos)
133+
DefinitionResultImpl(headSym, locations.asJava)
134+
135+
private def locationsForSymbol(
136+
symbol: Symbol,
137+
semanticdbSymbol: String,
138+
uri: URI,
139+
pos: SourcePosition
140+
)(using ctx: Context): List[Location] =
141+
val isLocal = symbol.source == pos.source
142+
if isLocal then
143+
val trees = driver.openedTrees(uri)
144+
val include = Include.definitions | Include.local
145+
val (exportedDefs, otherDefs) =
146+
Interactive.findTreesMatching(trees, include, symbol)
147+
.partition(_.tree.symbol.is(Exported))
148+
otherDefs.headOption.orElse(exportedDefs.headOption).collect:
149+
case srcTree if srcTree.namePos.exists =>
150+
new Location(params.uri().toString(), srcTree.namePos.toLsp)
151+
.toList
152+
else search.definition(semanticdbSymbol, uri).asScala.toList
163153

164154
def semanticSymbolsSorted(
165155
syms: List[Symbol]
166-
)(using ctx: Context): List[String] =
156+
)(using ctx: Context): List[(Symbol, String)] =
167157
syms
168-
.map { sym =>
158+
.collect { case sym if sym.exists =>
169159
// in case of having the same type and teerm symbol
170160
// term comes first
171161
// used only for ordering symbols that come from `Import`
172162
val termFlag =
173163
if sym.is(ModuleClass) then sym.sourceModule.isTerm
174164
else sym.isTerm
175-
(termFlag, SemanticdbSymbols.symbolName(sym))
165+
(termFlag, sym.sourceSymbol, SemanticdbSymbols.symbolName(sym))
176166
}
177-
.sorted
178-
.map(_._2)
167+
.sortBy { case (termFlag, _, name) => (termFlag, name) }
168+
.map(_.tail)
179169

180170
end PcDefinitionProvider

presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala

+72
Original file line numberDiff line numberDiff line change
@@ -539,3 +539,75 @@ class PcDefinitionSuite extends BasePcDefinitionSuite:
539539
|val foo_name = foo.na@@me
540540
|""".stripMargin
541541
)
542+
543+
@Test def `object` =
544+
check(
545+
"""|package a
546+
|object <<Bar>> {
547+
| def foo = 42
548+
|}
549+
|val m = B@@ar.foo
550+
|""".stripMargin
551+
)
552+
553+
@Test def i7267 =
554+
check(
555+
"""|package a
556+
|trait Foo {
557+
| def someNum: Int
558+
| def <<apply>>(i: Int): Unit = println(someNum)
559+
|}
560+
|object <<Bar>> extends Foo {
561+
| def someNum = 42
562+
|}
563+
|
564+
|object Test {
565+
| B@@ar(2)
566+
|}
567+
|""".stripMargin
568+
)
569+
570+
@Test def `i7267-2` =
571+
check(
572+
"""|package b
573+
|trait Foo {
574+
| def someNum: Int
575+
| def <<unapply>>(i: Int): Option[Int] = Some(i)
576+
|}
577+
|object <<Bar>> extends Foo {
578+
| def someNum = 42
579+
|}
580+
|
581+
|object Test {
582+
| Bar.someNum match {
583+
| case B@@ar(1) => ???
584+
| case _ =>
585+
| }
586+
|}
587+
|""".stripMargin
588+
)
589+
590+
@Test def `i7267-3` =
591+
check(
592+
"""|package c
593+
|case class <<Bar>>()
594+
|object <<Bar>>
595+
|object O {
596+
| val a = B@@ar()
597+
|}
598+
|""".stripMargin
599+
)
600+
601+
@Test def `i7267-4` =
602+
check(
603+
"""|package d
604+
|class <<Bar>>()
605+
|object <<Bar>> {
606+
| def <<apply>>(): Bar = new Bar()
607+
|}
608+
|object O {
609+
| val a = B@@ar()
610+
|}
611+
|""".stripMargin
612+
)
613+

0 commit comments

Comments
 (0)