@@ -48,6 +48,16 @@ case class Completion(label: String, description: String, symbols: List[Symbol])
48
48
49
49
object Completion :
50
50
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
+
51
61
/** Get possible completions from tree at `pos`
52
62
*
53
63
* @return offset and list of symbols for possible completions
@@ -60,7 +70,6 @@ object Completion:
60
70
val mode = completionMode(untpdPath, pos)
61
71
val rawPrefix = completionPrefix(untpdPath, pos)
62
72
val completions = rawCompletions(pos, mode, rawPrefix, tpdPath, untpdPath)
63
-
64
73
postProcessCompletions(untpdPath, completions, rawPrefix)
65
74
66
75
/** Get possible completions from tree at `pos`
@@ -89,7 +98,7 @@ object Completion:
89
98
*
90
99
* Otherwise, provide no completion suggestion.
91
100
*/
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 = path match
93
102
// Ignore `package foo@@` and `package foo.bar@@`
94
103
case ((_ : tpd.Select ) | (_ : tpd.Ident )):: (_ : tpd.PackageDef ) :: _ => Mode .None
95
104
case GenericImportSelector (sel) =>
@@ -102,11 +111,14 @@ object Completion:
102
111
case untpd.Literal (Constants .Constant (_ : String )) :: _ => Mode .Term | Mode .Scope // literal completions
103
112
case (ref : untpd.RefTree ) :: _ =>
104
113
val maybeSelectMembers = if ref.isInstanceOf [untpd.Select ] then Mode .Member else Mode .Scope
105
-
106
- if (ref.name.isTermName) Mode .Term | maybeSelectMembers
114
+ if (forSymbolSearch) then Mode . Term | Mode . Type | maybeSelectMembers
115
+ else if (ref.name.isTermName) Mode .Term | maybeSelectMembers
107
116
else if (ref.name.isTypeName) Mode .Type | maybeSelectMembers
108
117
else Mode .None
109
118
119
+ case (_ : tpd.TypeTree | _ : tpd.MemberDef ) :: _ if forSymbolSearch => Mode .Type | Mode .Term
120
+ case (_ : tpd.CaseDef ) :: _ if forSymbolSearch => Mode .Type | Mode .Term
121
+ case Nil if forSymbolSearch => Mode .Type | Mode .Term
110
122
case _ => Mode .None
111
123
112
124
/** When dealing with <errors> in varios palces we check to see if they are
@@ -174,12 +186,12 @@ object Completion:
174
186
case _ => None
175
187
176
188
private object StringContextApplication :
177
- def unapply (path : List [tpd.Tree ]): Option [tpd.Apply ] =
189
+ def unapply (path : List [tpd.Tree ]): Option [tpd.Apply ] =
178
190
path match
179
191
case tpd.Select (qual @ tpd.Apply (tpd.Select (tpd.Select (_, StdNames .nme.StringContext ), _), _), _) :: _ =>
180
192
Some (qual)
181
193
case _ => None
182
-
194
+
183
195
184
196
/** Inspect `path` to determine the offset where the completion result should be inserted. */
185
197
def completionOffset (untpdPath : List [untpd.Tree ]): Int =
@@ -230,14 +242,14 @@ object Completion:
230
242
val result = adjustedPath match
231
243
// Ignore synthetic select from `This` because in code it was `Ident`
232
244
// See example in dotty.tools.languageserver.CompletionTest.syntheticThis
233
- case tpd.Select (qual @ tpd.This (_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions
245
+ case tpd.Select (qual @ tpd.This (_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions.names
234
246
case StringContextApplication (qual) =>
235
- completer.scopeCompletions ++ completer.selectionCompletions(qual)
236
- case tpd.Select (qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
247
+ completer.scopeCompletions.names ++ completer.selectionCompletions(qual)
248
+ case tpd.Select (qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
237
249
completer.selectionCompletions(qual)
238
250
case tpd.Select (qual, _) :: _ => Map .empty
239
251
case (tree : tpd.ImportOrExport ) :: _ => completer.directMemberCompletions(tree.expr)
240
- case _ => completer.scopeCompletions
252
+ case _ => completer.scopeCompletions.names
241
253
242
254
interactiv.println(i """ completion info with pos = $pos,
243
255
| term = ${completer.mode.is(Mode .Term )},
@@ -338,6 +350,7 @@ object Completion:
338
350
(completionMode.is(Mode .Term ) && (sym.isTerm || sym.is(ModuleClass ))
339
351
|| (completionMode.is(Mode .Type ) && (sym.isType || sym.isStableMember)))
340
352
)
353
+ end isValidCompletionSymbol
341
354
342
355
given ScopeOrdering (using Context ): Ordering [Seq [SingleDenotation ]] with
343
356
val order =
@@ -371,7 +384,7 @@ object Completion:
371
384
* (even if the import follows it syntactically)
372
385
* - a more deeply nested import shadowing a member or a local definition causes an ambiguity
373
386
*/
374
- def scopeCompletions (using context : Context ): CompletionMap =
387
+ def scopeCompletions (using context : Context ): CompletionResult =
375
388
376
389
/** Temporary data structure representing denotations with the same name introduced in a given scope
377
390
* as a member of a type, by a local definition or by an import clause
@@ -382,14 +395,19 @@ object Completion:
382
395
ScopedDenotations (denots.filter(includeFn), ctx)
383
396
384
397
val mappings = collection.mutable.Map .empty[Name , List [ScopedDenotations ]].withDefaultValue(List .empty)
398
+ val renames = collection.mutable.Map .empty[Symbol , Name ]
385
399
def addMapping (name : Name , denots : ScopedDenotations ) =
386
400
mappings(name) = mappings(name) :+ denots
387
401
388
402
ctx.outersIterator.foreach { case ctx @ given Context =>
389
403
if ctx.isImportContext then
390
- importedCompletions.foreach { (name, denots) =>
404
+ val imported = importedCompletions
405
+ imported.names.foreach { (name, denots) =>
391
406
addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
392
407
}
408
+ imported.renames.foreach { (name, newName) =>
409
+ renames(name) = newName
410
+ }
393
411
else if ctx.owner.isClass then
394
412
accessibleMembers(ctx.owner.thisType)
395
413
.groupByName.foreach { (name, denots) =>
@@ -433,7 +451,6 @@ object Completion:
433
451
// most deeply nested member or local definition if not shadowed by an import
434
452
case Some (local) if local.ctx.scope == first.ctx.scope =>
435
453
resultMappings += name -> local.denots
436
-
437
454
case None if isSingleImport || isImportedInDifferentScope || isSameSymbolImportedDouble =>
438
455
resultMappings += name -> first.denots
439
456
case None if notConflictingWithDefaults =>
@@ -443,7 +460,7 @@ object Completion:
443
460
}
444
461
}
445
462
446
- resultMappings
463
+ CompletionResult ( resultMappings, renames.toMap)
447
464
end scopeCompletions
448
465
449
466
/** Widen only those types which are applied or are exactly nothing
@@ -485,15 +502,20 @@ object Completion:
485
502
/** Completions introduced by imports directly in this context.
486
503
* Completions from outer contexts are not included.
487
504
*/
488
- private def importedCompletions (using Context ): CompletionMap =
505
+ private def importedCompletions (using Context ): CompletionResult =
489
506
val imp = ctx.importInfo
507
+ val renames = collection.mutable.Map .empty[Symbol , Name ]
490
508
491
509
if imp == null then
492
- Map .empty
510
+ CompletionResult ( Map .empty, Map .empty)
493
511
else
494
512
def fromImport (name : Name , nameInScope : Name ): Seq [(Name , SingleDenotation )] =
495
513
imp.site.member(name).alternatives
496
- .collect { case denot if include(denot, nameInScope) => nameInScope -> denot }
514
+ .collect { case denot if include(denot, nameInScope) =>
515
+ if name != nameInScope then
516
+ renames(denot.symbol) = nameInScope
517
+ nameInScope -> denot
518
+ }
497
519
498
520
val givenImports = imp.importedImplicits
499
521
.map { ref => (ref.implicitName: Name , ref.underlyingRef.denot.asSingleDenotation) }
@@ -519,7 +541,8 @@ object Completion:
519
541
fromImport(original.toTypeName, nameInScope.toTypeName)
520
542
}.toSeq.groupByName
521
543
522
- givenImports ++ wildcardMembers ++ explicitMembers
544
+ val results = givenImports ++ wildcardMembers ++ explicitMembers
545
+ CompletionResult (results, renames.toMap)
523
546
end importedCompletions
524
547
525
548
/** Completions from implicit conversions including old style extensions using implicit classes */
@@ -597,7 +620,7 @@ object Completion:
597
620
598
621
// 1. The extension method is visible under a simple name, by being defined or inherited or imported in a scope enclosing the reference.
599
622
val termCompleter = new Completer (Mode .Term , pos, untpdPath, matches)
600
- val extMethodsInScope = termCompleter.scopeCompletions.toList.flatMap:
623
+ val extMethodsInScope = termCompleter.scopeCompletions.names. toList.flatMap:
601
624
case (name, denots) => denots.collect:
602
625
case d : SymDenotation if d.isTerm && d.termRef.symbol.is(Extension ) => (d.termRef, name.asTermName)
603
626
@@ -699,6 +722,7 @@ object Completion:
699
722
700
723
private type CompletionMap = Map [Name , Seq [SingleDenotation ]]
701
724
725
+ case class CompletionResult (names : Map [Name , Seq [SingleDenotation ]], renames : Map [Symbol , Name ])
702
726
/**
703
727
* The completion mode: defines what kinds of symbols should be included in the completion
704
728
* results.
0 commit comments