diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-09-03 12:38:54 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-09-03 14:10:40 +1000 |
commit | a67b04079716812004b0d44ad65d48c508cf7d9e (patch) | |
tree | 626bcec9c809a4e7583445f30c1392fa272f7db6 | |
parent | b6a812e0fa5bf333610884e72b0306f2bd7efee7 (diff) | |
download | scala-a67b04079716812004b0d44ad65d48c508cf7d9e.tar.gz scala-a67b04079716812004b0d44ad65d48c508cf7d9e.tar.bz2 scala-a67b04079716812004b0d44ad65d48c508cf7d9e.zip |
Add the prefix the autocompletion results (Scope-, TypeMember)
This makes life easier for clients of these APIs, we use this
to avoid passing this around in the wrapper result `TypeMembers`.
4 files changed, 24 insertions, 13 deletions
diff --git a/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala b/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala index fc6403afa3..586f011429 100644 --- a/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala @@ -268,6 +268,7 @@ trait CompilerControl { self: Global => /** Info given for every member found by completion */ abstract class Member { + def prefix: Type val sym: Symbol val tpe: Type val accessible: Boolean @@ -289,6 +290,8 @@ trait CompilerControl { self: Global => accessible: Boolean, inherited: Boolean, viaView: Symbol) extends Member { + // should be a case class parameter, but added as a var instead to preserve compatibility with the IDE + var prefix: Type = NoType override def implicitlyAdded = viaView != NoSymbol } @@ -296,7 +299,10 @@ trait CompilerControl { self: Global => sym: Symbol, tpe: Type, accessible: Boolean, - viaImport: Tree) extends Member + viaImport: Tree) extends Member { + // should be a case class parameter, but added as a var instead to preserve compatibility with the IDE + var prefix: Type = NoType + } // items that get sent to scheduler diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index d5caf28991..b9d06b3633 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -1031,10 +1031,12 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") def addScopeMember(sym: Symbol, pre: Type, viaImport: Tree) = locals.add(sym, pre, implicitlyAdded = false) { (s, st) => // imported val and var are always marked as inaccessible, but they could be accessed through their getters. SI-7995 - if (s.hasGetter) + val member = if (s.hasGetter) new ScopeMember(s, st, context.isAccessible(s.getter, pre, superAccess = false), viaImport) else new ScopeMember(s, st, context.isAccessible(s, pre, superAccess = false), viaImport) + member.prefix = pre + member } def localsToEnclosing() = { enclosing.addNonShadowed(locals) @@ -1101,10 +1103,13 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") def addTypeMember(sym: Symbol, pre: Type, inherited: Boolean, viaView: Symbol) = { val implicitlyAdded = viaView != NoSymbol members.add(sym, pre, implicitlyAdded) { (s, st) => - new TypeMember(s, st, + val result = new TypeMember(s, st, context.isAccessible(if (s.hasGetter) s.getter(s.owner) else s, pre, superAccess && !implicitlyAdded), inherited, viaView) + result.prefix = pre + result + } } @@ -1157,7 +1162,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") def matchingResults(matcher: (M, Name) => Boolean = CompletionResult.prefixMatcher): List[M] = { results filter (r => matcher(r, name)) } - def qualifierType: Type = NoType } object CompletionResult { final case class ScopeMembers(positionDelta: Int, results: List[ScopeMember], name: Name) extends CompletionResult { @@ -1165,7 +1169,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } final case class TypeMembers(positionDelta: Int, qualifier: Tree, tree: Tree, results: List[TypeMember], name: Name) extends CompletionResult { type M = TypeMember - override def qualifierType: Type = qualifier.tpe } case object NoResults extends CompletionResult { override def results = Nil diff --git a/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala b/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala index ee901db1a0..3fb4428e76 100644 --- a/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala +++ b/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala @@ -54,28 +54,27 @@ class PresentationCompilerCompleter(intp: IMain) extends Completion with ScalaCo Candidates(cursor, "" :: tpString :: Nil) } def candidates(result: Result): Candidates = { - import result.compiler.CompletionResult._, result.compiler.{Symbol, NoSymbol, Type, Member, NoType, Name} - def defStringCandidates(qualTpe: Type, matching: List[Member], name: Name): Candidates = { + import result.compiler._ + import CompletionResult._ + def defStringCandidates(matching: List[Member], name: Name): Candidates = { val defStrings = for { member <- matching if member.symNameDropLocal == name sym <- member.sym.alternatives sugared = sym.sugaredSymbolOrSelf } yield { - val tp = qualTpe match { - case NoType => member.tpe - case _ => qualTpe memberType sym - } + val tp = member.prefix memberType sym sugared.defStringSeenAs(tp) } Candidates(cursor, "" :: defStrings.distinct) } val found = result.completionsAt(cursor) match { case NoResults => Completion.NoCandidates - case r => val matching = r.matchingResults() + case r => + val matching = r.matchingResults() val tabAfterCommonPrefixCompletion = lastCommonPrefixCompletion.contains(buf.substring(0, cursor)) && matching.exists(_.symNameDropLocal == r.name) val doubleTab = tabCount > 0 && matching.forall(_.symNameDropLocal == r.name) - if (tabAfterCommonPrefixCompletion || doubleTab) defStringCandidates(r.qualifierType, matching, r.name) + if (tabAfterCommonPrefixCompletion || doubleTab) defStringCandidates(matching, r.name) else { if (matching.nonEmpty && matching.forall(_.symNameDropLocal == r.name)) Completion.NoCandidates // don't offer completion if the only option has been fully typed already diff --git a/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala b/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala index 70cb2882ba..8c72ed7b32 100644 --- a/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala +++ b/test/junit/scala/tools/nsc/interpreter/CompletionTest.scala @@ -94,6 +94,9 @@ class CompletionTest { // and performs as-seen-from with respect to the prefix checkExact(completer, "trait T[A]{ lazy val x_y_z: A }; class C extends T[Int] { x_y_z")() checkExact(completer, "trait T[A]{ lazy val x_y_z: A }; class C extends T[Int] { x_y_z")(EmptyString, "lazy val x_y_z: Int") + + checkExact(completer, "trait T[A] { def foo: A }; (t: T[Int]) => t.foo")() + checkExact(completer, "trait T[A] { def foo: A }; (t: T[Int]) => t.foo")(EmptyString, "def foo: Int") } @Test |