@@ -48,6 +48,16 @@ case class Completion(label: String, description: String, symbols: List[Symbol])
4848
4949object Completion :
5050
51+ def scopeContext (pos : SourcePosition )(using Context ): CompletionResult =
52+ val tpdPath = Interactive .pathTo(ctx.compilationUnit.tpdTree, pos.span)
53+ val completionContext = Interactive .contextOfPath(tpdPath).withPhase(Phases .typerPhase)
54+ inContext(completionContext):
55+ val untpdPath = Interactive .resolveTypedOrUntypedPath(tpdPath, pos)
56+ val mode = completionMode(untpdPath, pos, forSymbolSearch = true )
57+ val rawPrefix = completionPrefix(untpdPath, pos)
58+ val completer = new Completer (mode, pos, untpdPath, _ => true )
59+ completer.scopeCompletions
60+
5161 /** Get possible completions from tree at `pos`
5262 *
5363 * @return offset and list of symbols for possible completions
@@ -60,7 +70,6 @@ object Completion:
6070 val mode = completionMode(untpdPath, pos)
6171 val rawPrefix = completionPrefix(untpdPath, pos)
6272 val completions = rawCompletions(pos, mode, rawPrefix, tpdPath, untpdPath)
63-
6473 postProcessCompletions(untpdPath, completions, rawPrefix)
6574
6675 /** Get possible completions from tree at `pos`
@@ -89,7 +98,8 @@ object Completion:
8998 *
9099 * Otherwise, provide no completion suggestion.
91100 */
92- def completionMode (path : List [untpd.Tree ], pos : SourcePosition ): Mode = path match
101+ def completionMode (path : List [untpd.Tree ], pos : SourcePosition , forSymbolSearch : Boolean = false ): Mode =
102+ path match
93103 // Ignore `package foo@@` and `package foo.bar@@`
94104 case ((_ : tpd.Select ) | (_ : tpd.Ident )):: (_ : tpd.PackageDef ) :: _ => Mode .None
95105 case GenericImportSelector (sel) =>
@@ -102,11 +112,14 @@ object Completion:
102112 case untpd.Literal (Constants .Constant (_ : String )) :: _ => Mode .Term | Mode .Scope // literal completions
103113 case (ref : untpd.RefTree ) :: _ =>
104114 val maybeSelectMembers = if ref.isInstanceOf [untpd.Select ] then Mode .Member else Mode .Scope
105-
106- if (ref.name.isTermName) Mode .Term | maybeSelectMembers
115+ if (forSymbolSearch) then Mode . Term | Mode . Type | maybeSelectMembers
116+ else if (ref.name.isTermName) Mode .Term | maybeSelectMembers
107117 else if (ref.name.isTypeName) Mode .Type | maybeSelectMembers
108118 else Mode .None
109119
120+ case (_ : tpd.TypeTree | _ : tpd.MemberDef ) :: _ if forSymbolSearch => Mode .Type | Mode .Term
121+ case (_ : tpd.CaseDef ) :: _ if forSymbolSearch => Mode .Type | Mode .Term
122+ case Nil => Mode .Type | Mode .Term
110123 case _ => Mode .None
111124
112125 /** When dealing with <errors> in varios palces we check to see if they are
@@ -174,12 +187,12 @@ object Completion:
174187 case _ => None
175188
176189 private object StringContextApplication :
177- def unapply (path : List [tpd.Tree ]): Option [tpd.Apply ] =
190+ def unapply (path : List [tpd.Tree ]): Option [tpd.Apply ] =
178191 path match
179192 case tpd.Select (qual @ tpd.Apply (tpd.Select (tpd.Select (_, StdNames .nme.StringContext ), _), _), _) :: _ =>
180193 Some (qual)
181194 case _ => None
182-
195+
183196
184197 /** Inspect `path` to determine the offset where the completion result should be inserted. */
185198 def completionOffset (untpdPath : List [untpd.Tree ]): Int =
@@ -230,14 +243,14 @@ object Completion:
230243 val result = adjustedPath match
231244 // Ignore synthetic select from `This` because in code it was `Ident`
232245 // See example in dotty.tools.languageserver.CompletionTest.syntheticThis
233- case tpd.Select (qual @ tpd.This (_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions
246+ case tpd.Select (qual @ tpd.This (_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions.names
234247 case StringContextApplication (qual) =>
235- completer.scopeCompletions ++ completer.selectionCompletions(qual)
236- case tpd.Select (qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
248+ completer.scopeCompletions.names ++ completer.selectionCompletions(qual)
249+ case tpd.Select (qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
237250 completer.selectionCompletions(qual)
238251 case tpd.Select (qual, _) :: _ => Map .empty
239252 case (tree : tpd.ImportOrExport ) :: _ => completer.directMemberCompletions(tree.expr)
240- case _ => completer.scopeCompletions
253+ case _ => completer.scopeCompletions.names
241254
242255 interactiv.println(i """ completion info with pos = $pos,
243256 | term = ${completer.mode.is(Mode .Term )},
@@ -338,6 +351,7 @@ object Completion:
338351 (completionMode.is(Mode .Term ) && (sym.isTerm || sym.is(ModuleClass ))
339352 || (completionMode.is(Mode .Type ) && (sym.isType || sym.isStableMember)))
340353 )
354+ end isValidCompletionSymbol
341355
342356 given ScopeOrdering (using Context ): Ordering [Seq [SingleDenotation ]] with
343357 val order =
@@ -371,7 +385,7 @@ object Completion:
371385 * (even if the import follows it syntactically)
372386 * - a more deeply nested import shadowing a member or a local definition causes an ambiguity
373387 */
374- def scopeCompletions (using context : Context ): CompletionMap =
388+ def scopeCompletions (using context : Context ): CompletionResult =
375389
376390 /** Temporary data structure representing denotations with the same name introduced in a given scope
377391 * as a member of a type, by a local definition or by an import clause
@@ -382,14 +396,19 @@ object Completion:
382396 ScopedDenotations (denots.filter(includeFn), ctx)
383397
384398 val mappings = collection.mutable.Map .empty[Name , List [ScopedDenotations ]].withDefaultValue(List .empty)
399+ val renames = collection.mutable.Map .empty[Symbol , Name ]
385400 def addMapping (name : Name , denots : ScopedDenotations ) =
386401 mappings(name) = mappings(name) :+ denots
387402
388403 ctx.outersIterator.foreach { case ctx @ given Context =>
389404 if ctx.isImportContext then
390- importedCompletions.foreach { (name, denots) =>
405+ val imported = importedCompletions
406+ imported.names.foreach { (name, denots) =>
391407 addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
392408 }
409+ imported.renames.foreach { (name, newName) =>
410+ renames(name) = newName
411+ }
393412 else if ctx.owner.isClass then
394413 accessibleMembers(ctx.owner.thisType)
395414 .groupByName.foreach { (name, denots) =>
@@ -433,7 +452,6 @@ object Completion:
433452 // most deeply nested member or local definition if not shadowed by an import
434453 case Some (local) if local.ctx.scope == first.ctx.scope =>
435454 resultMappings += name -> local.denots
436-
437455 case None if isSingleImport || isImportedInDifferentScope || isSameSymbolImportedDouble =>
438456 resultMappings += name -> first.denots
439457 case None if notConflictingWithDefaults =>
@@ -443,7 +461,7 @@ object Completion:
443461 }
444462 }
445463
446- resultMappings
464+ CompletionResult ( resultMappings, renames.toMap)
447465 end scopeCompletions
448466
449467 /** Widen only those types which are applied or are exactly nothing
@@ -485,15 +503,20 @@ object Completion:
485503 /** Completions introduced by imports directly in this context.
486504 * Completions from outer contexts are not included.
487505 */
488- private def importedCompletions (using Context ): CompletionMap =
506+ private def importedCompletions (using Context ): CompletionResult =
489507 val imp = ctx.importInfo
508+ val renames = collection.mutable.Map .empty[Symbol , Name ]
490509
491510 if imp == null then
492- Map .empty
511+ CompletionResult ( Map .empty, Map .empty)
493512 else
494513 def fromImport (name : Name , nameInScope : Name ): Seq [(Name , SingleDenotation )] =
495514 imp.site.member(name).alternatives
496- .collect { case denot if include(denot, nameInScope) => nameInScope -> denot }
515+ .collect { case denot if include(denot, nameInScope) =>
516+ if name != nameInScope then
517+ renames(denot.symbol) = nameInScope
518+ nameInScope -> denot
519+ }
497520
498521 val givenImports = imp.importedImplicits
499522 .map { ref => (ref.implicitName: Name , ref.underlyingRef.denot.asSingleDenotation) }
@@ -519,7 +542,8 @@ object Completion:
519542 fromImport(original.toTypeName, nameInScope.toTypeName)
520543 }.toSeq.groupByName
521544
522- givenImports ++ wildcardMembers ++ explicitMembers
545+ val results = givenImports ++ wildcardMembers ++ explicitMembers
546+ CompletionResult (results, renames.toMap)
523547 end importedCompletions
524548
525549 /** Completions from implicit conversions including old style extensions using implicit classes */
@@ -597,7 +621,7 @@ object Completion:
597621
598622 // 1. The extension method is visible under a simple name, by being defined or inherited or imported in a scope enclosing the reference.
599623 val termCompleter = new Completer (Mode .Term , pos, untpdPath, matches)
600- val extMethodsInScope = termCompleter.scopeCompletions.toList.flatMap:
624+ val extMethodsInScope = termCompleter.scopeCompletions.names. toList.flatMap:
601625 case (name, denots) => denots.collect:
602626 case d : SymDenotation if d.isTerm && d.termRef.symbol.is(Extension ) => (d.termRef, name.asTermName)
603627
@@ -699,6 +723,7 @@ object Completion:
699723
700724 private type CompletionMap = Map [Name , Seq [SingleDenotation ]]
701725
726+ case class CompletionResult (names : Map [Name , Seq [SingleDenotation ]], renames : Map [Symbol , Name ])
702727 /**
703728 * The completion mode: defines what kinds of symbols should be included in the completion
704729 * results.
0 commit comments