@@ -156,15 +156,15 @@ object Interactive {
156
156
157
157
/** Get possible completions from tree at `pos`
158
158
*
159
- * @return offset and list of symbols for possible completions
159
+ * @return offset and list of (symbol, name in scope) for possible completions
160
160
*/
161
- def completions (pos : SourcePosition )(implicit ctx : Context ): (Int , List [Symbol ]) = {
161
+ def completions (pos : SourcePosition )(implicit ctx : Context ): (Int , List [( Symbol , Name ) ]) = {
162
162
val path = pathTo(ctx.compilationUnit.tpdTree, pos.pos)
163
163
computeCompletions(pos, path)(contextOfPath(path))
164
164
}
165
165
166
- private def computeCompletions (pos : SourcePosition , path : List [Tree ])(implicit ctx : Context ): (Int , List [Symbol ]) = {
167
- val completions = Scopes .newScope.openForMutations
166
+ private def computeCompletions (pos : SourcePosition , path : List [Tree ])(implicit ctx : Context ): (Int , List [( Symbol , Name ) ]) = {
167
+ val completions = new RenameAwareScope
168
168
169
169
val (completionPos, prefix, termOnly, typeOnly) = path match {
170
170
case (ref : RefTree ) :: _ =>
@@ -188,53 +188,53 @@ object Interactive {
188
188
* as completion results. However, if a user explicitly writes all '$' characters in an
189
189
* identifier, we should complete the rest.
190
190
*/
191
- def include (sym : Symbol ) =
192
- sym.name .startsWith(prefix) &&
193
- ! sym.name .toString.drop(prefix.length).contains('$' ) &&
191
+ def include (sym : Symbol , nameInScope : Name ) =
192
+ nameInScope .startsWith(prefix) &&
193
+ ! nameInScope .toString.drop(prefix.length).contains('$' ) &&
194
194
(! termOnly || sym.isTerm) &&
195
195
(! typeOnly || sym.isType)
196
196
197
- def enter (sym : Symbol ) =
198
- if (include(sym)) completions.enter(sym)
197
+ def enter (sym : Symbol , nameInScope : Name ) =
198
+ if (include(sym, nameInScope )) completions.enter(sym, nameInScope )
199
199
200
200
def add (sym : Symbol ) =
201
- if (sym.exists && ! completions.lookup(sym.name).exists) enter(sym)
201
+ if (sym.exists && ! completions.lookup(sym.name).exists) enter(sym, sym.name )
202
202
203
- def addMember (site : Type , name : Name ) =
204
- if (! completions.lookup(name ).exists)
205
- for (alt <- site.member(name).alternatives) enter(alt.symbol)
203
+ def addMember (site : Type , name : Name , nameInScope : Name ) =
204
+ if (! completions.lookup(nameInScope ).exists)
205
+ for (alt <- site.member(name).alternatives) enter(alt.symbol, nameInScope )
206
206
207
207
def accessibleMembers (site : Type , superAccess : Boolean = true ): Seq [Symbol ] = site match {
208
208
case site : NamedType if site.symbol.is(Package ) =>
209
- site.decls.toList.filter(include) // Don't look inside package members -- it's too expensive.
209
+ site.decls.toList.filter(sym => include(sym, sym.name) ) // Don't look inside package members -- it's too expensive.
210
210
case _ =>
211
211
def appendMemberSyms (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
212
212
try buf ++= site.member(name).alternatives
213
213
catch { case ex : TypeError => }
214
214
site.memberDenots(takeAllFilter, appendMemberSyms).collect {
215
- case mbr if include(mbr.symbol) => mbr.accessibleFrom(site, superAccess).symbol
215
+ case mbr if include(mbr.symbol, mbr.symbol.name ) => mbr.accessibleFrom(site, superAccess).symbol
216
216
case _ => NoSymbol
217
217
}.filter(_.exists)
218
218
}
219
219
220
220
def addAccessibleMembers (site : Type , superAccess : Boolean = true ): Unit =
221
- for (mbr <- accessibleMembers(site)) addMember(site, mbr.name)
221
+ for (mbr <- accessibleMembers(site)) addMember(site, mbr.name, mbr.name )
222
222
223
223
def getImportCompletions (ictx : Context ): Unit = {
224
224
implicit val ctx = ictx
225
225
val imp = ctx.importInfo
226
226
if (imp != null ) {
227
- def addImport (name : TermName ) = {
228
- addMember(imp.site, name)
229
- addMember(imp.site, name.toTypeName)
227
+ def addImport (original : TermName , nameInScope : TermName ) = {
228
+ addMember(imp.site, original, nameInScope)
229
+ addMember(imp.site, original.toTypeName, nameInScope.toTypeName)
230
+ }
231
+ imp.reverseMapping.foreachBinding { (nameInScope, original) =>
232
+ if (original != nameInScope || ! imp.excluded.contains(original))
233
+ addImport(original, nameInScope)
230
234
}
231
- // FIXME: We need to also take renamed items into account for completions,
232
- // That means we have to return list of a pairs (Name, Symbol) instead of a list
233
- // of symbols from `completions`.!=
234
- for (imported <- imp.originals if ! imp.excluded.contains(imported)) addImport(imported)
235
235
if (imp.isWildcardImport)
236
236
for (mbr <- accessibleMembers(imp.site) if ! imp.excluded.contains(mbr.name.toTermName))
237
- addMember(imp.site, mbr.name)
237
+ addMember(imp.site, mbr.name, mbr.name )
238
238
}
239
239
}
240
240
@@ -279,7 +279,7 @@ object Interactive {
279
279
case _ => getScopeCompletions(ctx)
280
280
}
281
281
282
- val completionList = completions.toList
282
+ val completionList = completions.toListWithNames
283
283
interactiv.println(i " completion with pos = $pos, prefix = $prefix, termOnly = $termOnly, typeOnly = $typeOnly = $completionList%, % " )
284
284
(completionPos, completionList)
285
285
}
@@ -293,7 +293,7 @@ object Interactive {
293
293
def addMember (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
294
294
buf ++= prefix.member(name).altsWith(sym =>
295
295
! exclude(sym) && sym.isAccessibleFrom(prefix)(boundaryCtx))
296
- prefix.memberDenots(completionsFilter, addMember).map(_.symbol).toList
296
+ prefix.memberDenots(completionsFilter, addMember).map(_.symbol).toList
297
297
}
298
298
else Nil
299
299
}
@@ -572,4 +572,23 @@ object Interactive {
572
572
n0.stripModuleClassSuffix.toTermName eq n1.stripModuleClassSuffix.toTermName
573
573
}
574
574
575
+ /** A scope that tracks renames of the entered symbols.
576
+ * Useful for providing completions for renamed symbols
577
+ * in the REPL and the IDE.
578
+ */
579
+ private class RenameAwareScope extends Scopes .MutableScope {
580
+ private [this ] val renames : mutable.Map [Symbol , Name ] = mutable.Map .empty
581
+
582
+ /** Enter the symbol `sym` in this scope, recording a potential renaming. */
583
+ def enter [T <: Symbol ](sym : T , name : Name )(implicit ctx : Context ): T = {
584
+ if (name != sym.name) renames += sym -> name
585
+ newScopeEntry(name, sym)
586
+ sym
587
+ }
588
+
589
+ /** Lists the symbols in this scope along with the name associated with them. */
590
+ def toListWithNames (implicit ctx : Context ): List [(Symbol , Name )] =
591
+ toList.map(sym => (sym, renames.get(sym).getOrElse(sym.name)))
592
+ }
593
+
575
594
}
0 commit comments