@@ -137,7 +137,7 @@ object Completion {
137
137
138
138
private class CompletionBuffer (val mode : Mode , val prefix : String , pos : SourcePosition ) {
139
139
140
- private [this ] val completions = Scopes .newScope.openForMutations
140
+ private [this ] val completions = new RenameAwareScope
141
141
142
142
/**
143
143
* Return the list of symbols that shoudl be included in completion results.
@@ -146,7 +146,11 @@ object Completion {
146
146
* the same `Completion`.
147
147
*/
148
148
def getCompletions (implicit ctx : Context ): List [Completion ] = {
149
- val groupedSymbols = completions.toList.groupBy(_.name.stripModuleClassSuffix.toSimpleName).toList
149
+ val groupedSymbols = {
150
+ val symbols = completions.toListWithNames
151
+ val nameToSymbols = symbols.groupBy(_._2.stripModuleClassSuffix.toSimpleName)
152
+ nameToSymbols.mapValues(_.map(_._1)).toList
153
+ }
150
154
groupedSymbols.map { case (name, symbols) =>
151
155
val typesFirst = symbols.sortWith((s, _) => s.isType)
152
156
// Use distinct to remove duplicates with class, module class, etc.
@@ -173,11 +177,11 @@ object Completion {
173
177
if (ctx.owner.isClass) {
174
178
addAccessibleMembers(ctx.owner.thisType)
175
179
ctx.owner.asClass.classInfo.selfInfo match {
176
- case selfSym : Symbol => add(selfSym)
180
+ case selfSym : Symbol => add(selfSym, selfSym.name )
177
181
case _ =>
178
182
}
179
183
}
180
- else if (ctx.scope != null ) ctx.scope.foreach(add)
184
+ else if (ctx.scope != null ) ctx.scope.foreach(s => add(s, s.name) )
181
185
182
186
addImportCompletions
183
187
@@ -208,15 +212,16 @@ object Completion {
208
212
* If `sym` exists, no symbol with the same name is already included, and it satisfies the
209
213
* inclusion filter, then add it to the completions.
210
214
*/
211
- private def add (sym : Symbol )(implicit ctx : Context ) =
212
- if (sym.exists && ! completions.lookup(sym.name ).exists && include(sym)) {
213
- completions.enter(sym)
215
+ private def add (sym : Symbol , nameInScope : Name )(implicit ctx : Context ) =
216
+ if (sym.exists && ! completions.lookup(nameInScope ).exists && include(sym, nameInScope )) {
217
+ completions.enter(sym, nameInScope )
214
218
}
215
219
216
220
/** Lookup members `name` from `site`, and try to add them to the completion list. */
217
- private def addMember (site : Type , name : Name )(implicit ctx : Context ) =
218
- if (! completions.lookup(name).exists)
219
- for (alt <- site.member(name).alternatives) add(alt.symbol)
221
+ private def addMember (site : Type , name : Name , nameInScope : Name )(implicit ctx : Context ) =
222
+ if (! completions.lookup(nameInScope).exists) {
223
+ for (alt <- site.member(name).alternatives) add(alt.symbol, nameInScope)
224
+ }
220
225
221
226
/** Include in completion sets only symbols that
222
227
* 1. start with given name prefix, and
@@ -230,9 +235,9 @@ object Completion {
230
235
* as completion results. However, if a user explicitly writes all '$' characters in an
231
236
* identifier, we should complete the rest.
232
237
*/
233
- private def include (sym : Symbol )(implicit ctx : Context ): Boolean =
234
- sym.name .startsWith(prefix) &&
235
- ! sym.name .toString.drop(prefix.length).contains('$' ) &&
238
+ private def include (sym : Symbol , nameInScope : Name )(implicit ctx : Context ): Boolean =
239
+ nameInScope .startsWith(prefix) &&
240
+ ! nameInScope .toString.drop(prefix.length).contains('$' ) &&
236
241
! sym.isPrimaryConstructor &&
237
242
(! sym.is(Package ) || ! sym.moduleClass.exists) &&
238
243
! sym.is(allOf(Mutable , Accessor )) &&
@@ -249,20 +254,20 @@ object Completion {
249
254
*/
250
255
private def accessibleMembers (site : Type )(implicit ctx : Context ): Seq [Symbol ] = site match {
251
256
case site : NamedType if site.symbol.is(Package ) =>
252
- site.decls.toList.filter(include) // Don't look inside package members -- it's too expensive.
257
+ site.decls.toList.filter(sym => include(sym, sym.name) ) // Don't look inside package members -- it's too expensive.
253
258
case _ =>
254
259
def appendMemberSyms (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
255
260
try buf ++= site.member(name).alternatives
256
261
catch { case ex : TypeError => }
257
262
site.memberDenots(takeAllFilter, appendMemberSyms).collect {
258
- case mbr if include(mbr.symbol) => mbr.accessibleFrom(site, superAccess = true ).symbol
263
+ case mbr if include(mbr.symbol, mbr.symbol.name ) => mbr.accessibleFrom(site, superAccess = true ).symbol
259
264
case _ => NoSymbol
260
265
}.filter(_.exists)
261
266
}
262
267
263
268
/** Add all the accessible members of `site` in `info`. */
264
269
private def addAccessibleMembers (site : Type )(implicit ctx : Context ): Unit =
265
- for (mbr <- accessibleMembers(site)) addMember(site, mbr.name)
270
+ for (mbr <- accessibleMembers(site)) addMember(site, mbr.name, mbr.name )
266
271
267
272
/**
268
273
* Add in `info` the symbols that are imported by `ctx.importInfo`. If this is a wildcard import,
@@ -271,17 +276,18 @@ object Completion {
271
276
private def addImportCompletions (implicit ctx : Context ): Unit = {
272
277
val imp = ctx.importInfo
273
278
if (imp != null ) {
274
- def addImport (name : TermName ) = {
275
- addMember(imp.site, name)
276
- addMember(imp.site, name.toTypeName)
279
+ def addImport (name : TermName , nameInScope : TermName ) = {
280
+ addMember(imp.site, name, nameInScope)
281
+ addMember(imp.site, name.toTypeName, nameInScope.toTypeName)
282
+ }
283
+ imp.reverseMapping.foreachBinding { (nameInScope, original) =>
284
+ if (original != nameInScope || ! imp.excluded.contains(original)) {
285
+ addImport(original, nameInScope)
286
+ }
277
287
}
278
- // FIXME: We need to also take renamed items into account for completions,
279
- // That means we have to return list of a pairs (Name, Symbol) instead of a list
280
- // of symbols from `completions`.!=
281
- for (imported <- imp.originals if ! imp.excluded.contains(imported)) addImport(imported)
282
288
if (imp.isWildcardImport)
283
289
for (mbr <- accessibleMembers(imp.site) if ! imp.excluded.contains(mbr.name.toTermName))
284
- addMember(imp.site, mbr.name)
290
+ addMember(imp.site, mbr.name, mbr.name )
285
291
}
286
292
}
287
293
@@ -324,4 +330,23 @@ object Completion {
324
330
val Import : Mode = new Mode (4 ) | Term | Type
325
331
}
326
332
333
+ /** A scope that tracks renames of the entered symbols.
334
+ * Useful for providing completions for renamed symbols
335
+ * in the REPL and the IDE.
336
+ */
337
+ private class RenameAwareScope extends Scopes .MutableScope {
338
+ private [this ] val renames : mutable.Map [Symbol , Name ] = mutable.Map .empty
339
+
340
+ /** Enter the symbol `sym` in this scope, recording a potential renaming. */
341
+ def enter [T <: Symbol ](sym : T , name : Name )(implicit ctx : Context ): T = {
342
+ if (name != sym.name) renames += sym -> name
343
+ newScopeEntry(name, sym)
344
+ sym
345
+ }
346
+
347
+ /** Lists the symbols in this scope along with the name associated with them. */
348
+ def toListWithNames (implicit ctx : Context ): List [(Symbol , Name )] =
349
+ toList.map(sym => (sym, renames.get(sym).getOrElse(sym.name)))
350
+ }
351
+
327
352
}
0 commit comments