diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index bfb42b1a5395..b6feab31a269 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -8,6 +8,7 @@ import scala.collection._ import ast.{NavigateAST, Trees, tpd, untpd} import core._, core.Decorators.{sourcePos => _, _} import Contexts._, Flags._, Names._, NameOps._, Symbols._, Trees._, Types._ +import transform.SymUtils.decorateSymbol import util.Positions._, util.SourceFile, util.SourcePosition import core.Denotations.SingleDenotation import NameKinds.SimpleNameKind @@ -33,6 +34,7 @@ object Interactive { def isDefinitions: Boolean = (bits & definitions.bits) != 0 def isLinkedClass: Boolean = (bits & linkedClass.bits) != 0 def isImports: Boolean = (bits & imports.bits) != 0 + def isLocal: Boolean = (bits & local.bits) != 0 } /** The empty set */ @@ -59,6 +61,9 @@ object Interactive { /** Include imports in the results */ val imports: Set = Set(1 << 5) + /** Include local symbols, inspect local trees */ + val local: Set = Set(1 << 6) + /** All the flags */ val all: Set = Set(~0) } @@ -321,12 +326,25 @@ object Interactive { * * @param includeReferences If true, include references and not just definitions */ - def namedTrees(trees: List[SourceTree], include: Include.Set, treePredicate: NameTree => Boolean) - (implicit ctx: Context): List[SourceTree] = safely { + def namedTrees(trees: List[SourceTree], + include: Include.Set, + treePredicate: NameTree => Boolean = util.common.alwaysTrue + )(implicit ctx: Context): List[SourceTree] = safely { val buf = new mutable.ListBuffer[SourceTree] def traverser(source: SourceFile) = { new untpd.TreeTraverser { + private def handle(utree: untpd.NameTree): Unit = { + val tree = utree.asInstanceOf[tpd.NameTree] + if (tree.symbol.exists + && !tree.symbol.is(Synthetic) + && !tree.symbol.isPrimaryConstructor + && tree.pos.exists + && !tree.pos.isZeroExtent + && (include.isReferences || isDefinition(tree)) + && treePredicate(tree)) + buf += SourceTree(tree, source) + } override def traverse(tree: untpd.Tree)(implicit ctx: Context) = { tree match { case imp: untpd.Import if include.isImports && tree.hasType => @@ -334,16 +352,11 @@ object Interactive { val selections = tpd.importSelections(tree) traverse(imp.expr) selections.foreach(traverse) + case utree: untpd.ValOrDefDef if tree.hasType => + handle(utree) + if (include.isLocal) traverseChildren(tree) case utree: untpd.NameTree if tree.hasType => - val tree = utree.asInstanceOf[tpd.NameTree] - if (tree.symbol.exists - && !tree.symbol.is(Synthetic) - && !tree.symbol.isPrimaryConstructor - && tree.pos.exists - && !tree.pos.isZeroExtent - && (include.isReferences || isDefinition(tree)) - && treePredicate(tree)) - buf += SourceTree(tree, source) + handle(utree) traverseChildren(tree) case tree: untpd.Inlined => traverse(tree.call) @@ -474,6 +487,7 @@ object Interactive { def findDefinitions(path: List[Tree], pos: SourcePosition, driver: InteractiveDriver)(implicit ctx: Context): List[SourceTree] = { enclosingSourceSymbols(path, pos).flatMap { sym => val enclTree = enclosingTree(path) + val includeLocal = if (sym.exists && sym.isLocal) Include.local else Include.empty val (trees, include) = if (enclTree.isInstanceOf[MemberDef]) @@ -492,7 +506,7 @@ object Interactive { (Nil, Include.empty) } - findTreesMatching(trees, include, sym) + findTreesMatching(trees, include | includeLocal, sym) } } diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index f2578f978b82..a8dd44db60fb 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -22,7 +22,6 @@ import core._, core.Decorators.{sourcePos => _, _} import Comments._, Constants._, Contexts._, Flags._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._ import classpath.ClassPathEntries import reporting._, reporting.diagnostic.{Message, MessageContainer, messages} -import transform.SymUtils.decorateSymbol import typer.Typer import util.{Set => _, _} import interactive._, interactive.InteractiveDriver._ @@ -312,7 +311,7 @@ class DottyLanguageServer extends LanguageServer val includes = { val includeDeclaration = params.getContext.isIncludeDeclaration - Include.references | Include.overriding | Include.imports | + Include.references | Include.overriding | Include.imports | Include.local | (if (includeDeclaration) Include.definitions else Include.empty) } @@ -457,9 +456,8 @@ class DottyLanguageServer extends LanguageServer implicit val ctx = driver.currentCtx val uriTrees = driver.openedTrees(uri) - val predicate = (tree: NameTree) => !tree.symbol.isLocal - val defs = Interactive.namedTrees(uriTrees, Include.empty, predicate) + val defs = Interactive.namedTrees(uriTrees, Include.empty) (for { d <- defs if !isWorksheetWrapper(d) info <- symbolInfo(d.tree.symbol, d.namePos, positionMapperFor(d.source)) @@ -468,16 +466,12 @@ class DottyLanguageServer extends LanguageServer override def symbol(params: WorkspaceSymbolParams) = computeAsync { cancelToken => val query = params.getQuery - def predicate(implicit ctx: Context): NameTree => Boolean = { tree => - val sym = tree.symbol - !sym.isLocal && tree.name.toString.contains(query) - } drivers.values.toList.flatMap { driver => implicit val ctx = driver.currentCtx val trees = driver.sourceTreesContaining(query) - val defs = Interactive.namedTrees(trees, Include.empty, predicate) + val defs = Interactive.namedTrees(trees, Include.empty, _.name.toString.contains(query)) defs.flatMap(d => symbolInfo(d.tree.symbol, d.namePos, positionMapperFor(d.source))) }.asJava } @@ -505,7 +499,7 @@ class DottyLanguageServer extends LanguageServer val predicates = definitions.map(Interactive.implementationFilter(_)(ctx)) tree => predicates.exists(_(tree)) } - val matches = Interactive.namedTrees(trees, Include.empty, predicate)(ctx) + val matches = Interactive.namedTrees(trees, Include.local, predicate)(ctx) matches.map(tree => location(tree.namePos(ctx), positionMapperFor(tree.source))) } }.toList diff --git a/language-server/test/dotty/tools/languageserver/ReferencesTest.scala b/language-server/test/dotty/tools/languageserver/ReferencesTest.scala index bfe811b2751e..b99947bfe9bb 100644 --- a/language-server/test/dotty/tools/languageserver/ReferencesTest.scala +++ b/language-server/test/dotty/tools/languageserver/ReferencesTest.scala @@ -346,4 +346,14 @@ class ReferencesTest { .references(m11 to m12, List(m9 to m10, m11 to m12), withDecl = false) } + @Test def referenceInsideLocalMember: Unit = { + withSources( + code"""object A { + | val ${m1}foo${m2} = 0 + | def fizz = println(${m3}foo${m4}) + |}""" + ).references(m1 to m2, List(m1 to m2, m3 to m4), withDecl = true) + .references(m1 to m2, List(m3 to m4), withDecl = false) + } + }