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