@@ -156,15 +156,15 @@ object Interactive {
156156
157157 /** Get possible completions from tree at `pos`
158158 *
159- * @return offset and list of symbols for possible completions
159+ * @return offset and list of (symbol, name in scope) for possible completions
160160 */
161- def completions (pos : SourcePosition )(implicit ctx : Context ): (Int , List [Symbol ]) = {
161+ def completions (pos : SourcePosition )(implicit ctx : Context ): (Int , List [( Symbol , Name ) ]) = {
162162 val path = pathTo(ctx.compilationUnit.tpdTree, pos.pos)
163163 computeCompletions(pos, path)(contextOfPath(path))
164164 }
165165
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
168168
169169 val (completionPos, prefix, termOnly, typeOnly) = path match {
170170 case (ref : RefTree ) :: _ =>
@@ -188,53 +188,53 @@ object Interactive {
188188 * as completion results. However, if a user explicitly writes all '$' characters in an
189189 * identifier, we should complete the rest.
190190 */
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('$' ) &&
194194 (! termOnly || sym.isTerm) &&
195195 (! typeOnly || sym.isType)
196196
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 )
199199
200200 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 )
202202
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 )
206206
207207 def accessibleMembers (site : Type , superAccess : Boolean = true ): Seq [Symbol ] = site match {
208208 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.
210210 case _ =>
211211 def appendMemberSyms (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
212212 try buf ++= site.member(name).alternatives
213213 catch { case ex : TypeError => }
214214 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
216216 case _ => NoSymbol
217217 }.filter(_.exists)
218218 }
219219
220220 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 )
222222
223223 def getImportCompletions (ictx : Context ): Unit = {
224224 implicit val ctx = ictx
225225 val imp = ctx.importInfo
226226 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)
230234 }
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)
235235 if (imp.isWildcardImport)
236236 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 )
238238 }
239239 }
240240
@@ -279,7 +279,7 @@ object Interactive {
279279 case _ => getScopeCompletions(ctx)
280280 }
281281
282- val completionList = completions.toList
282+ val completionList = completions.toListWithNames
283283 interactiv.println(i " completion with pos = $pos, prefix = $prefix, termOnly = $termOnly, typeOnly = $typeOnly = $completionList%, % " )
284284 (completionPos, completionList)
285285 }
@@ -293,7 +293,7 @@ object Interactive {
293293 def addMember (name : Name , buf : mutable.Buffer [SingleDenotation ]): Unit =
294294 buf ++= prefix.member(name).altsWith(sym =>
295295 ! exclude(sym) && sym.isAccessibleFrom(prefix)(boundaryCtx))
296- prefix.memberDenots(completionsFilter, addMember).map(_.symbol).toList
296+ prefix.memberDenots(completionsFilter, addMember).map(_.symbol).toList
297297 }
298298 else Nil
299299 }
@@ -572,4 +572,23 @@ object Interactive {
572572 n0.stripModuleClassSuffix.toTermName eq n1.stripModuleClassSuffix.toTermName
573573 }
574574
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+
575594}
0 commit comments