Skip to content

Commit 8345131

Browse files
committed
change mock symbol search
1 parent 4429d73 commit 8345131

File tree

3 files changed

+110
-34
lines changed

3 files changed

+110
-34
lines changed

Diff for: presentation-compiler/src/main/dotty/tools/pc/CompilerSearchVisitor.scala

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import dotty.tools.dotc.core.Contexts.*
1212
import dotty.tools.dotc.core.Flags
1313
import dotty.tools.dotc.core.Names.*
1414
import dotty.tools.dotc.core.Symbols.*
15+
import dotty.tools.pc.utils.InteractiveEnrichments.companion
1516

1617
class CompilerSearchVisitor(
1718
visitSymbol: Symbol => Boolean
@@ -91,11 +92,12 @@ class CompilerSearchVisitor(
9192
range: org.eclipse.lsp4j.Range
9293
): Int =
9394
val gsym = SemanticdbSymbols.inverseSemanticdbSymbol(symbol).headOption
94-
gsym
95-
.filter(isAccessible)
96-
.map(visitSymbol)
97-
.map(_ => 1)
98-
.getOrElse(0)
95+
val matching = for
96+
sym0 <- gsym.toList
97+
sym <- if sym0.companion.is(Flags.Synthetic) then List(sym0, sym0.companion) else List(sym0)
98+
if isAccessible(sym)
99+
yield visitSymbol(sym)
100+
matching.size
99101

100102
def shouldVisitPackage(pkg: String): Boolean =
101103
isAccessible(requiredPackage(normalizePackage(pkg)))

Diff for: presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWorkspaceSuite.scala

+10
Original file line numberDiff line numberDiff line change
@@ -937,3 +937,13 @@ class CompletionWorkspaceSuite extends BaseCompletionSuite:
937937
|""".stripMargin,
938938
""
939939
)
940+
941+
@Test def `metals-i6593` =
942+
check(
943+
"""|package a:
944+
| class UniqueObject
945+
|package b:
946+
| val i = Uniq@@
947+
|""".stripMargin,
948+
"UniqueObject(): UniqueObject - a"
949+
)
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,62 @@
11
package dotty.tools.pc.utils
22

3+
import dotty.tools.dotc.ast.untpd.*
4+
import dotty.tools.dotc.core.Contexts.Context
5+
import dotty.tools.dotc.core.Flags
6+
import dotty.tools.dotc.interactive.InteractiveDriver
7+
import dotty.tools.pc.CompilerSearchVisitor
8+
import dotty.tools.pc.utils.InteractiveEnrichments.decoded
9+
310
import java.io.File
411
import java.nio.file.Paths
5-
612
import scala.collection.mutable
7-
import scala.meta.internal.metals.{
8-
CompilerVirtualFileParams,
9-
Fuzzy,
10-
WorkspaceSymbolQuery
11-
}
12-
import scala.meta.pc.SymbolSearchVisitor
1313
import scala.language.unsafeNulls
14+
import scala.meta.internal.metals.CompilerVirtualFileParams
15+
import scala.meta.internal.metals.Fuzzy
16+
import scala.meta.internal.metals.WorkspaceSymbolQuery
17+
import scala.meta.pc.SymbolSearchVisitor
1418

15-
import dotty.tools.dotc.core.Contexts.Context
16-
import dotty.tools.dotc.core.Symbols.*
17-
import dotty.tools.dotc.interactive.InteractiveDriver
18-
import dotty.tools.dotc.semanticdb.SemanticSymbolBuilder
19-
import dotty.tools.pc.CompilerSearchVisitor
19+
import TestingWorkspaceSearch.*
2020

2121
object TestingWorkspaceSearch:
2222
def empty: TestingWorkspaceSearch = new TestingWorkspaceSearch(Nil)
23+
class Disambiguator:
24+
val nameMap = mutable.Map[String, Int]()
25+
def methodPart(name: String) =
26+
val i = nameMap.getOrElse(name, 0)
27+
nameMap.put(name, i + 1)
28+
if i == 0 then "()."
29+
else s"(+$i)."
30+
31+
case class ParentSymbol(symbol: SearchSymbol, fileName: String):
32+
private val dis: Disambiguator = new Disambiguator
33+
private def isPackage = symbol.lastOption.exists(_.suffix == "/")
34+
private def isMethod = symbol.lastOption.exists(_.suffix.endsWith(")."))
35+
private def isInit = symbol.lastOption.exists(_.name == "<init>")
36+
private def filePackage = SymbolPart(fileName, "$package.")
37+
private def member(part: SymbolPart)=
38+
if isPackage then Some(symbol :+ filePackage :+ part)
39+
else if isMethod then
40+
if isInit then Some(symbol.dropRight(1) :+ part)
41+
else None
42+
else Some(symbol :+ part)
43+
def makeMethod(newPart: String) = member(SymbolPart(newPart, dis.methodPart(newPart)))
44+
def makeVal(newPart: String) =
45+
member(SymbolPart(newPart, "."))
46+
def makeTypeAlias(newPart: String) = member(SymbolPart(newPart, "#"))
47+
def makeType(newPart: String) = symbol :+ SymbolPart(newPart, "#")
48+
def makeTerm(newPart: String) = symbol :+ SymbolPart(newPart, ".")
49+
def makePackage(parts: List[String]) =
50+
parts match
51+
case "<empty>" :: Nil => List(SymbolPart("_empty_", "/"))
52+
case list if symbol.map(_.name) == List("_empty_") => list.map(SymbolPart(_, "/"))
53+
case list => symbol ++ list.map(SymbolPart(_, "/"))
54+
55+
object ParentSymbol:
56+
def empty(fileName: String) = ParentSymbol(Nil, fileName)
57+
58+
case class SymbolPart(name: String, suffix: String)
59+
type SearchSymbol = List[SymbolPart]
2360

2461
class TestingWorkspaceSearch(classpath: Seq[String]):
2562
val inputs: mutable.Map[String, String] = mutable.Map.empty[String, String]
@@ -30,8 +67,39 @@ class TestingWorkspaceSearch(classpath: Seq[String]):
3067
defaultFlags ++
3168
List("-classpath", classpath.mkString(File.pathSeparator))
3269

70+
private class SymbolCollector extends UntypedTreeAccumulator[List[Tree]]:
71+
override def apply(x: List[Tree], tree: Tree)(using Context): List[Tree] = tree :: x
72+
73+
private def newSymbol(tree: Tree, parent: ParentSymbol)(using Context): Option[SearchSymbol] =
74+
tree match
75+
case PackageDef(name, _) =>
76+
Some(parent.makePackage(namesFromSelect(name).reverse))
77+
case ModuleDef(name, _) =>
78+
Some(parent.makeTerm(name.decoded))
79+
case ValDef(name, _, _) =>
80+
parent.makeVal(name.decoded)
81+
case t @ TypeDef(name, _: Template) if !t.mods.is(Flags.Implicit) =>
82+
Some(parent.makeType(name.decoded))
83+
case TypeDef(name, _) =>
84+
parent.makeTypeAlias(name.decoded)
85+
case DefDef(name, _, _, _) =>
86+
parent.makeMethod(name.decoded)
87+
case _ => None
88+
89+
def traverse(acc: List[SearchSymbol], tree: Tree, parent: ParentSymbol)(using Context): List[SearchSymbol] =
90+
val symbol = newSymbol(tree, parent)
91+
val res = symbol.filter(_.lastOption.exists(_.suffix != "/")).map(_ :: acc).getOrElse(acc)
92+
val children = foldOver(Nil, tree).reverse
93+
val newParent = symbol.map(ParentSymbol(_, parent.fileName)).getOrElse(parent)
94+
children.foldLeft(res)((a, c) => traverse(a, c, newParent))
95+
3396
val driver = new InteractiveDriver(settings)
3497

98+
private def namesFromSelect(select: Tree)(using Context): List[String] =
99+
select match
100+
case Select(qual, name) => name.decoded :: namesFromSelect(qual)
101+
case Ident(name) => List(name.decoded)
102+
35103
def search(
36104
query: WorkspaceSymbolQuery,
37105
visitor: SymbolSearchVisitor,
@@ -41,21 +109,17 @@ class TestingWorkspaceSearch(classpath: Seq[String]):
41109

42110
visitor match
43111
case visitor: CompilerSearchVisitor =>
44-
inputs.map { (path, text) =>
45-
46-
val nioPath = Paths.get(path)
47-
val uri = nioPath.toUri()
48-
val symbols = DefSymbolCollector(driver, CompilerVirtualFileParams(uri, text)).namedDefSymbols
49-
50-
// We have to map symbol from this Context, to one in PresentationCompiler
51-
// To do it we are searching it with semanticdb symbol
52-
val semanticSymbolBuilder = SemanticSymbolBuilder()
53-
symbols
54-
.filter((symbol, _) => filter(symbol))
55-
.filter((_, name) => Fuzzy.matches(query.query, name))
56-
.map(symbol => semanticSymbolBuilder.symbolName(symbol._1))
57-
.map(
58-
visitor.visitWorkspaceSymbol(Paths.get(""), _, null, null)
59-
)
60-
}
112+
inputs.map: (path, text) =>
113+
val nio = Paths.get(path)
114+
val uri = nio.toUri()
115+
driver.run(uri, text)
116+
val run = driver.currentCtx.run
117+
val unit = run.units.head
118+
val symbols = SymbolCollector().traverse(Nil, unit.untpdTree, ParentSymbol.empty(nio.getFileName().toString().stripSuffix(".scala")))
119+
symbols.foreach: sym =>
120+
val name = sym.last.name
121+
if Fuzzy.matches(query.query, name)
122+
then
123+
val symbolsString = sym.map{ case SymbolPart(name, suffix) => name ++ suffix}.mkString
124+
visitor.visitWorkspaceSymbol(Paths.get(""), symbolsString, null, null)
61125
case _ =>

0 commit comments

Comments
 (0)