Skip to content

Commit 2d8e711

Browse files
committed
Support multiple imports per line
1 parent 503fa1b commit 2d8e711

File tree

4 files changed

+78
-26
lines changed

4 files changed

+78
-26
lines changed

compiler/src/dotty/tools/dotc/interactive/Interactive.scala

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -322,20 +322,23 @@ object Interactive {
322322

323323
def traverser(source: SourceFile) = {
324324
new untpd.TreeTraverser {
325-
private def handleImport(imported: List[Symbol],
326-
uexpr: untpd.Tree,
327-
id: untpd.Ident,
328-
rename: Option[untpd.Ident]): Unit = {
329-
val expr = uexpr.asInstanceOf[tpd.Tree]
325+
private def handleImport(imp: tpd.Import): Unit = {
326+
val imported =
327+
imp.selectors.flatMap {
328+
case id: untpd.Ident =>
329+
importedSymbols(imp.expr, id.name).map((_, id, None))
330+
case Thicket((id: untpd.Ident) :: (newName: untpd.Ident) :: Nil) =>
331+
importedSymbols(imp.expr, id.name).map((_, id, Some(newName)))
332+
}
330333
imported match {
331334
case Nil =>
332-
traverse(expr)
335+
traverse(imp.expr)
333336
case syms =>
334-
syms.foreach { sym =>
335-
val tree = tpd.Select(expr, sym.name).withPos(id.pos)
337+
syms.foreach { case (sym, name, rename) =>
338+
val tree = tpd.Select(imp.expr, sym.name).withPos(name.pos)
336339
val renameTree = rename.map { r =>
337340
val name = if (sym.name.isTypeName) r.name.toTypeName else r.name
338-
RenameTree(name, tpd.Select(expr, sym.name)).withPos(r.pos)
341+
RenameTree(name, tpd.Select(imp.expr, sym.name)).withPos(r.pos)
339342
}
340343
renameTree.foreach(traverse)
341344
traverse(tree)
@@ -344,12 +347,8 @@ object Interactive {
344347
}
345348
override def traverse(tree: untpd.Tree)(implicit ctx: Context) = {
346349
tree match {
347-
case imp @ Import(uexpr, (id: untpd.Ident) :: Nil) if includeImports =>
348-
val imported = importedSymbols(imp.asInstanceOf[tpd.Import])
349-
handleImport(imported, uexpr, id, None)
350-
case imp @ Import(uexpr, Thicket((id: untpd.Ident) :: (rename: untpd.Ident) :: Nil) :: Nil) if includeImports =>
351-
val imported = importedSymbols(imp.asInstanceOf[tpd.Import])
352-
handleImport(imported, uexpr, id, Some(rename))
350+
case imp: untpd.Import if includeImports =>
351+
handleImport(imp.asInstanceOf[tpd.Import])
353352
case utree: untpd.NameTree if tree.hasType =>
354353
val tree = utree.asInstanceOf[tpd.NameTree]
355354
if (tree.symbol.exists
@@ -522,25 +521,33 @@ object Interactive {
522521
private def importedSymbols(imp: tpd.Import,
523522
selectorPredicate: untpd.Tree => Boolean = util.common.alwaysTrue)
524523
(implicit ctx: Context): List[Symbol] = {
525-
def lookup0(name: Name): Symbol = imp.expr.tpe.member(name).symbol
526-
def lookup(name: Name): List[Symbol] = {
527-
lookup0(name.toTermName) ::
528-
lookup0(name.toTypeName) ::
529-
lookup0(name.moduleClassName) ::
530-
lookup0(name.sourceModuleName) :: Nil
531-
}
532-
533524
val symbols = imp.selectors.find(selectorPredicate) match {
534525
case Some(id: untpd.Ident) =>
535-
lookup(id.name)
526+
importedSymbols(imp.expr, id.name)
536527
case Some(Thicket((id: untpd.Ident) :: (_: untpd.Ident) :: Nil)) =>
537-
lookup(id.name)
538-
case _ => Nil
528+
importedSymbols(imp.expr, id.name)
529+
case _ =>
530+
Nil
539531
}
540532

541533
symbols.map(sourceSymbol).filter(_.exists).distinct
542534
}
543535

536+
/**
537+
* The symbols that are imported with `expr.name`
538+
*
539+
* @param expr The base of the import statement
540+
* @param name The name that is being imported.
541+
* @return All the symbols that would be imported with `expr.name`.
542+
*/
543+
private def importedSymbols(expr: tpd.Tree, name: Name)(implicit ctx: Context): List[Symbol] = {
544+
def lookup(name: Name): Symbol = expr.tpe.member(name).symbol
545+
lookup(name.toTermName) ::
546+
lookup(name.toTypeName) ::
547+
lookup(name.moduleClassName) ::
548+
lookup(name.sourceModuleName) :: Nil
549+
}
550+
544551
/**
545552
* Used to represent a renaming import `{foo => bar}`.
546553
* We need this because the name of the tree must be the new name, but the

language-server/test/dotty/tools/languageserver/DefinitionTest.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,17 @@ class DefinitionTest {
279279
.definition(m11 to m12, List(m3 to m4))
280280
}
281281

282+
@Test def multipleImportsPerLineWithRename: Unit = {
283+
withSources(
284+
code"""object A { class ${m1}B${m2}; class ${m3}C${m4} }""",
285+
code"""import A.{${m5}B${m6} => ${m7}B2${m8}, ${m9}C${m10} => ${m11}C2${m12}}
286+
class E"""
287+
).definition(m1 to m2, List(m1 to m2))
288+
.definition(m3 to m4, List(m3 to m4))
289+
.definition(m5 to m6, List(m1 to m2))
290+
.definition(m7 to m8, List(m1 to m2))
291+
.definition(m9 to m10, List(m3 to m4))
292+
.definition(m11 to m12, List(m3 to m4))
293+
}
294+
282295
}

language-server/test/dotty/tools/languageserver/HighlightTest.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,17 @@ class HighlightTest {
113113
.highlight(m7 to m8, (m1 to m2, DocumentHighlightKind.Read), (m3 to m4, DocumentHighlightKind.Read), (m5 to m6, DocumentHighlightKind.Read), (m7 to m8, DocumentHighlightKind.Read))
114114
}
115115

116+
@Test def multipleImportsPerLineWithRename: Unit = {
117+
withSources(
118+
code"""object A { class ${m1}B${m2}; class ${m3}C${m4} }
119+
import A.{${m5}B${m6} => ${m7}B2${m8}, ${m9}C${m10} => ${m11}C2${m12}}
120+
class E"""
121+
).highlight(m1 to m2, (m1 to m2, DocumentHighlightKind.Read), (m5 to m6, DocumentHighlightKind.Read), (m7 to m8, DocumentHighlightKind.Read))
122+
.highlight(m3 to m4, (m3 to m4, DocumentHighlightKind.Read), (m9 to m10, DocumentHighlightKind.Read), (m11 to m12, DocumentHighlightKind.Read))
123+
.highlight(m5 to m6, (m1 to m2, DocumentHighlightKind.Read), (m5 to m6, DocumentHighlightKind.Read), (m7 to m8, DocumentHighlightKind.Read))
124+
.highlight(m7 to m8, (m1 to m2, DocumentHighlightKind.Read), (m5 to m6, DocumentHighlightKind.Read), (m7 to m8, DocumentHighlightKind.Read))
125+
.highlight(m9 to m10, (m3 to m4, DocumentHighlightKind.Read), (m9 to m10, DocumentHighlightKind.Read), (m11 to m12, DocumentHighlightKind.Read))
126+
.highlight(m11 to m12, (m3 to m4, DocumentHighlightKind.Read), (m9 to m10, DocumentHighlightKind.Read), (m11 to m12, DocumentHighlightKind.Read))
127+
}
128+
116129
}

language-server/test/dotty/tools/languageserver/ReferencesTest.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,23 @@ class ReferencesTest {
158158
.references(m7 to m8, List(m5 to m6, m7 to m8), withDecl = false)
159159
}
160160

161+
@Test def multipleImportsPerLineWithRename: Unit = {
162+
withSources(
163+
code"""object A { class ${m1}B${m2}; class ${m3}C${m4} }""",
164+
code"""import A.{${m5}B${m6} => ${m7}B2${m8}, ${m9}C${m10} => ${m11}C2${m12}}
165+
class E"""
166+
).references(m1 to m2, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true)
167+
.references(m1 to m2, List(m5 to m6, m7 to m8), withDecl = false)
168+
.references(m3 to m4, List(m3 to m4, m9 to m10, m11 to m12), withDecl = true)
169+
.references(m3 to m4, List(m9 to m10, m11 to m12), withDecl = false)
170+
.references(m5 to m6, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true)
171+
.references(m5 to m6, List(m5 to m6, m7 to m8), withDecl = false)
172+
.references(m7 to m8, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true)
173+
.references(m7 to m8, List(m5 to m6, m7 to m8), withDecl = false)
174+
.references(m9 to m10, List(m3 to m4, m9 to m10, m11 to m12), withDecl = true)
175+
.references(m9 to m10, List(m9 to m10, m11 to m12), withDecl = false)
176+
.references(m11 to m12, List(m3 to m4, m9 to m10, m11 to m12), withDecl = true)
177+
.references(m11 to m12, List(m9 to m10, m11 to m12), withDecl = false)
178+
}
179+
161180
}

0 commit comments

Comments
 (0)