@@ -147,15 +147,15 @@ object Interactive {
147147
148148 /** Get possible completions from tree at `pos`
149149 *
150- * @return offset and list of symbols for possible completions
150+ * @return offset and list of (symbol, name in scope) for possible completions
151151 */
152- def completions (pos : SourcePosition )(implicit ctx : Context ): (Int , List [Symbol ]) = {
152+ def completions (pos : SourcePosition )(implicit ctx : Context ): (Int , List [( Symbol , Name ) ]) = {
153153 val path = pathTo(ctx.compilationUnit.tpdTree, pos.pos)
154154 computeCompletions(pos, path)(contextOfPath(path))
155155 }
156156
157- private def computeCompletions (pos : SourcePosition , path : List [Tree ])(implicit ctx : Context ): (Int , List [Symbol ]) = {
158- val completions = Scopes .newScope.openForMutations
157+ private def computeCompletions (pos : SourcePosition , path : List [Tree ])(implicit ctx : Context ): (Int , List [( Symbol , Name ) ]) = {
158+ val completions = new RenameAwareScope
159159
160160 val (completionPos, prefix, termOnly, typeOnly) = path match {
161161 case (ref : RefTree ) :: _ =>
@@ -179,53 +179,53 @@ object Interactive {
179179 * as completion results. However, if a user explicitly writes all '$' characters in an
180180 * identifier, we should complete the rest.
181181 */
182- def include (sym : Symbol ) =
183- sym.name .startsWith(prefix) &&
184- ! sym.name .toString.drop(prefix.length).contains('$' ) &&
182+ def include (sym : Symbol , nameInScope : Name ) =
183+ nameInScope .startsWith(prefix) &&
184+ ! nameInScope .toString.drop(prefix.length).contains('$' ) &&
185185 (! termOnly || sym.isTerm) &&
186186 (! typeOnly || sym.isType)
187187
188- def enter (sym : Symbol ) =
189- if (include(sym)) completions.enter(sym)
188+ def enter (sym : Symbol , nameInScope : Name ) =
189+ if (include(sym, nameInScope )) completions.enter(sym, nameInScope )
190190
191191 def add (sym : Symbol ) =
192- if (sym.exists && ! completions.lookup(sym.name).exists) enter(sym)
192+ if (sym.exists && ! completions.lookup(sym.name).exists) enter(sym, sym.name )
193193
194- def addMember (site : Type , name : Name ) =
195- if (! completions.lookup(name ).exists)
196- for (alt <- site.member(name).alternatives) enter(alt.symbol)
194+ def addMember (site : Type , name : Name , nameInScope : Name ) =
195+ if (! completions.lookup(nameInScope ).exists)
196+ for (alt <- site.member(name).alternatives) enter(alt.symbol, nameInScope )
197197
198198 def accessibleMembers (site : Type , superAccess : Boolean = true ): Seq [Symbol ] = site match {
199199 case site : NamedType if site.symbol.is(Package ) =>
200- site.decls.toList.filter(include) // Don't look inside package members -- it's too expensive.
200+ site.decls.toList.filter(sym => include(sym, sym.name) ) // Don't look inside package members -- it's too expensive.
201201 case _ =>
202202 def appendMemberSyms (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
203203 try buf ++= site.member(name).alternatives
204204 catch { case ex : TypeError => }
205205 site.memberDenots(takeAllFilter, appendMemberSyms).collect {
206- case mbr if include(mbr.symbol) => mbr.accessibleFrom(site, superAccess).symbol
206+ case mbr if include(mbr.symbol, mbr.symbol.name ) => mbr.accessibleFrom(site, superAccess).symbol
207207 case _ => NoSymbol
208208 }.filter(_.exists)
209209 }
210210
211211 def addAccessibleMembers (site : Type , superAccess : Boolean = true ): Unit =
212- for (mbr <- accessibleMembers(site)) addMember(site, mbr.name)
212+ for (mbr <- accessibleMembers(site)) addMember(site, mbr.name, mbr.name )
213213
214214 def getImportCompletions (ictx : Context ): Unit = {
215215 implicit val ctx = ictx
216216 val imp = ctx.importInfo
217217 if (imp != null ) {
218- def addImport (name : TermName ) = {
219- addMember(imp.site, name)
220- addMember(imp.site, name.toTypeName)
218+ def addImport (original : TermName , nameInScope : TermName ) = {
219+ addMember(imp.site, original, nameInScope)
220+ addMember(imp.site, original.toTypeName, nameInScope.toTypeName)
221+ }
222+ imp.reverseMapping.foreachBinding { (nameInScope, original) =>
223+ if (original != nameInScope || ! imp.excluded.contains(original))
224+ addImport(original, nameInScope)
221225 }
222- // FIXME: We need to also take renamed items into account for completions,
223- // That means we have to return list of a pairs (Name, Symbol) instead of a list
224- // of symbols from `completions`.!=
225- for (imported <- imp.originals if ! imp.excluded.contains(imported)) addImport(imported)
226226 if (imp.isWildcardImport)
227227 for (mbr <- accessibleMembers(imp.site) if ! imp.excluded.contains(mbr.name.toTermName))
228- addMember(imp.site, mbr.name)
228+ addMember(imp.site, mbr.name, mbr.name )
229229 }
230230 }
231231
@@ -270,7 +270,7 @@ object Interactive {
270270 case _ => getScopeCompletions(ctx)
271271 }
272272
273- val completionList = completions.toList
273+ val completionList = completions.toListWithNames
274274 interactiv.println(i " completion with pos = $pos, prefix = $prefix, termOnly = $termOnly, typeOnly = $typeOnly = $completionList%, % " )
275275 (completionPos, completionList)
276276 }
@@ -284,7 +284,7 @@ object Interactive {
284284 def addMember (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
285285 buf ++= prefix.member(name).altsWith(sym =>
286286 ! exclude(sym) && sym.isAccessibleFrom(prefix)(boundaryCtx))
287- prefix.memberDenots(completionsFilter, addMember).map(_.symbol).toList
287+ prefix.memberDenots(completionsFilter, addMember).map(_.symbol).toList
288288 }
289289 else Nil
290290 }
@@ -490,4 +490,23 @@ object Interactive {
490490 }
491491 }
492492
493+ /** A scope that tracks renames of the entered symbols.
494+ * Useful for providing completions for renamed symbols
495+ * in the REPL and the IDE.
496+ */
497+ private class RenameAwareScope extends Scopes .MutableScope {
498+ private [this ] val renames : mutable.Map [Symbol , Name ] = mutable.Map .empty
499+
500+ /** Enter the symbol `sym` in this scope, recording a potential renaming. */
501+ def enter [T <: Symbol ](sym : T , name : Name )(implicit ctx : Context ): T = {
502+ if (name != sym.name) renames += sym -> name
503+ newScopeEntry(name, sym)
504+ sym
505+ }
506+
507+ /** Lists the symbols in this scope along with the name associated with them. */
508+ def toListWithNames (implicit ctx : Context ): List [(Symbol , Name )] =
509+ toList.map(sym => (sym, renames.get(sym).getOrElse(sym.name)))
510+ }
511+
493512}
0 commit comments