Skip to content

Commit 560b6c0

Browse files
committed
Move helpers for handling imports to tpd.scala
1 parent 13f21cb commit 560b6c0

File tree

4 files changed

+94
-94
lines changed

4 files changed

+94
-94
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,5 +1147,65 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11471147
case _ =>
11481148
EmptyTree
11491149
}
1150+
1151+
/**
1152+
* The symbols that are imported with `expr.name`
1153+
*
1154+
* @param expr The base of the import statement
1155+
* @param name The name that is being imported.
1156+
* @return All the symbols that would be imported with `expr.name`.
1157+
*/
1158+
def importedSymbols(expr: Tree, name: Name)(implicit ctx: Context): List[Symbol] = {
1159+
def lookup(name: Name): Symbol = expr.tpe.member(name).symbol
1160+
List(lookup(name.toTermName),
1161+
lookup(name.toTypeName),
1162+
lookup(name.moduleClassName),
1163+
lookup(name.sourceModuleName))
1164+
}
1165+
1166+
/**
1167+
* All the symbols that are imported by the first selector of `imp` that matches
1168+
* `selectorPredicate`.
1169+
*
1170+
* @param imp The import statement to analyze
1171+
* @param selectorPredicate A test to find the selector to use.
1172+
* @return The symbols imported.
1173+
*/
1174+
def importedSymbols(imp: Import,
1175+
selectorPredicate: untpd.Tree => Boolean = util.common.alwaysTrue)
1176+
(implicit ctx: Context): List[Symbol] = {
1177+
val symbols = imp.selectors.find(selectorPredicate) match {
1178+
case Some(id: untpd.Ident) =>
1179+
importedSymbols(imp.expr, id.name)
1180+
case Some(Thicket((id: untpd.Ident) :: (_: untpd.Ident) :: Nil)) =>
1181+
importedSymbols(imp.expr, id.name)
1182+
case _ =>
1183+
Nil
1184+
}
1185+
1186+
symbols.map(_.sourceSymbol).filter(_.exists).distinct
1187+
}
1188+
1189+
def importSelections(imp: Import)(implicit ctx: Context): List[Select] = {
1190+
val imported =
1191+
imp.selectors.flatMap {
1192+
case id: untpd.Ident =>
1193+
importedSymbols(imp.expr, id.name).map((_, id, None))
1194+
case Thicket((id: untpd.Ident) :: (newName: untpd.Ident) :: Nil) =>
1195+
val renaming = Some(newName)
1196+
importedSymbols(imp.expr, id.name).map((_, id, renaming))
1197+
}
1198+
imported.flatMap { case (symbol, name, rename) =>
1199+
val tree = Select(imp.expr, symbol.name).withPos(name.pos)
1200+
val renameTree = rename.map { r =>
1201+
// Get the type of the symbol that is actually selected, and construct a select
1202+
// node with the new name and the type of the real symbol.
1203+
val name = if (symbol.name.isTypeName) r.name.toTypeName else r.name
1204+
val actual = Select(imp.expr, symbol.name)
1205+
Select(imp.expr, name).withPos(r.pos).withType(actual.tpe)
1206+
}
1207+
tree :: renameTree.toList
1208+
}
1209+
}
11501210
}
11511211

compiler/src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,26 @@ object Symbols {
624624
}
625625
}
626626

627+
/** A symbol related to `sym` that is defined in source code.
628+
*
629+
* @see enclosingSourceSymbols
630+
*/
631+
@annotation.tailrec final def sourceSymbol(implicit ctx: Context): Symbol =
632+
if (!denot.exists)
633+
this
634+
else if (denot.is(ModuleVal))
635+
this.moduleClass.sourceSymbol // The module val always has a zero-extent position
636+
else if (denot.is(Synthetic)) {
637+
val linked = denot.linkedClass
638+
if (linked.exists && !linked.is(Synthetic))
639+
linked
640+
else
641+
denot.owner.sourceSymbol
642+
}
643+
else if (denot.isPrimaryConstructor)
644+
denot.owner.sourceSymbol
645+
else this
646+
627647
/** The position of this symbol, or NoPosition if the symbol was not loaded
628648
* from source or from TASTY. This is always a zero-extent position.
629649
*

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

Lines changed: 6 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -97,29 +97,9 @@ object Interactive {
9797
List(enclosingTree(path).symbol)
9898
}
9999

100-
syms.map(Interactive.sourceSymbol).filter(_.exists)
100+
syms.map(_.sourceSymbol).filter(_.exists)
101101
}
102102

103-
/** A symbol related to `sym` that is defined in source code.
104-
*
105-
* @see enclosingSourceSymbols
106-
*/
107-
@tailrec def sourceSymbol(sym: Symbol)(implicit ctx: Context): Symbol =
108-
if (!sym.exists)
109-
sym
110-
else if (sym.is(ModuleVal))
111-
sourceSymbol(sym.moduleClass) // The module val always has a zero-extent position
112-
else if (sym.is(Synthetic)) {
113-
val linked = sym.linkedClass
114-
if (linked.exists && !linked.is(Synthetic))
115-
linked
116-
else
117-
sourceSymbol(sym.owner)
118-
}
119-
else if (sym.isPrimaryConstructor)
120-
sourceSymbol(sym.owner)
121-
else sym
122-
123103
/** Check if `tree` matches `sym`.
124104
* This is the case if the symbol defined by `tree` equals `sym`,
125105
* or the source symbol of tree equals sym,
@@ -132,7 +112,7 @@ object Interactive {
132112
sym1.owner.derivesFrom(sym2.owner) && sym1.overriddenSymbol(sym2.owner.asClass) == sym2
133113

134114
( sym == tree.symbol
135-
|| sym.exists && sym == sourceSymbol(tree.symbol)
115+
|| sym.exists && sym == tree.symbol.sourceSymbol
136116
|| include != 0 && sym.name == tree.symbol.name && sym.maybeOwner != tree.symbol.maybeOwner
137117
&& ( (include & Include.overridden) != 0 && overrides(sym, tree.symbol)
138118
|| (include & Include.overriding) != 0 && overrides(tree.symbol, sym)
@@ -327,37 +307,12 @@ object Interactive {
327307

328308
def traverser(source: SourceFile) = {
329309
new untpd.TreeTraverser {
330-
private def handleImport(imp: tpd.Import): Unit = {
331-
val imported =
332-
imp.selectors.flatMap {
333-
case id: untpd.Ident =>
334-
importedSymbols(imp.expr, id.name).map((_, id, None))
335-
case Thicket((id: untpd.Ident) :: (newName: untpd.Ident) :: Nil) =>
336-
val renaming = if (includeRenamingImports) Some(newName) else None
337-
importedSymbols(imp.expr, id.name).map((_, id, renaming))
338-
}
339-
imported match {
340-
case Nil =>
341-
traverse(imp.expr)
342-
case syms =>
343-
syms.foreach { case (sym, name, rename) =>
344-
val tree = tpd.Select(imp.expr, sym.name).withPos(name.pos)
345-
val renameTree = rename.map { r =>
346-
// Get the type of the symbol that is actually selected, and construct a select
347-
// node with the new name and the type of the real symbol.
348-
val name = if (sym.name.isTypeName) r.name.toTypeName else r.name
349-
val actual = tpd.Select(imp.expr, sym.name)
350-
tpd.Select(imp.expr, name).withPos(r.pos).withType(actual.tpe)
351-
}
352-
renameTree.foreach(traverse)
353-
traverse(tree)
354-
}
355-
}
356-
}
357310
override def traverse(tree: untpd.Tree)(implicit ctx: Context) = {
358311
tree match {
359-
case imp: untpd.Import if includeImports =>
360-
handleImport(imp.asInstanceOf[tpd.Import])
312+
case imp: untpd.Import if includeImports && tree.hasType =>
313+
val tree = imp.asInstanceOf[tpd.Import]
314+
val selections = tpd.importSelections(tree)
315+
selections.foreach(traverse)
361316
case utree: untpd.NameTree if tree.hasType =>
362317
val tree = utree.asInstanceOf[tpd.NameTree]
363318
if (tree.symbol.exists
@@ -572,44 +527,6 @@ object Interactive {
572527
}
573528
}
574529

575-
/**
576-
* All the symbols that are imported by import statement `imp`, if it matches
577-
* the predicate `selectorPredicate`.
578-
*
579-
* @param imp The import statement to analyze
580-
* @param selectorPredicate A test to find the selector to use.
581-
* @return The symbols imported.
582-
*/
583-
private def importedSymbols(imp: tpd.Import,
584-
selectorPredicate: untpd.Tree => Boolean = util.common.alwaysTrue)
585-
(implicit ctx: Context): List[Symbol] = {
586-
val symbols = imp.selectors.find(selectorPredicate) match {
587-
case Some(id: untpd.Ident) =>
588-
importedSymbols(imp.expr, id.name)
589-
case Some(Thicket((id: untpd.Ident) :: (_: untpd.Ident) :: Nil)) =>
590-
importedSymbols(imp.expr, id.name)
591-
case _ =>
592-
Nil
593-
}
594-
595-
symbols.map(sourceSymbol).filter(_.exists).distinct
596-
}
597-
598-
/**
599-
* The symbols that are imported with `expr.name`
600-
*
601-
* @param expr The base of the import statement
602-
* @param name The name that is being imported.
603-
* @return All the symbols that would be imported with `expr.name`.
604-
*/
605-
private def importedSymbols(expr: tpd.Tree, name: Name)(implicit ctx: Context): List[Symbol] = {
606-
def lookup(name: Name): Symbol = expr.tpe.member(name).symbol
607-
List(lookup(name.toTermName),
608-
lookup(name.toTypeName),
609-
lookup(name.moduleClassName),
610-
lookup(name.sourceModuleName))
611-
}
612-
613530
/**
614531
* Is this tree using a renaming introduced by an import statement?
615532
*

language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -417,11 +417,14 @@ class DottyLanguageServer extends LanguageServer
417417

418418
if (tp.isError || tpw == NoType) null // null here indicates that no response should be sent
419419
else {
420-
val symbol = Interactive.enclosingSourceSymbols(path, pos).headOption.orNull
421-
if (symbol == null) return null
422-
val docComment = ParsedComment.docOf(symbol)
423-
val content = hoverContent(Some(tpw.show), docComment)
424-
new Hover(content, null)
420+
Interactive.enclosingSourceSymbols(path, pos) match {
421+
case Nil =>
422+
null
423+
case symbol :: _ =>
424+
val docComment = ParsedComment.docOf(symbol)
425+
val content = hoverContent(Some(tpw.show), docComment)
426+
new Hover(content, null)
427+
}
425428
}
426429
}
427430

0 commit comments

Comments
 (0)