summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interactive/scala/tools/nsc/interactive/ContextTrees.scala64
-rw-r--r--test/files/presentation/scope-completion-import.check141
-rw-r--r--test/files/presentation/scope-completion-import/Test.scala3
-rw-r--r--test/files/presentation/scope-completion-import/src/Completions.scala64
4 files changed, 248 insertions, 24 deletions
diff --git a/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala b/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala
index 93ef4c4d6c..4f67a22b8f 100644
--- a/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala
+++ b/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala
@@ -6,6 +6,7 @@ package scala.tools.nsc
package interactive
import scala.collection.mutable.ArrayBuffer
+import scala.annotation.tailrec
trait ContextTrees { self: Global =>
@@ -28,44 +29,59 @@ trait ContextTrees { self: Global =>
override def toString = "ContextTree("+pos+", "+children+")"
}
- /** Optionally returns the smallest context that contains given `pos`, or None if none exists.
+ /** Returns the most precise context possible for the given `pos`.
+ *
+ * It looks for the finest ContextTree containing `pos`, and then look inside
+ * this ContextTree for a child ContextTree located immediately before `pos`.
+ * If such a child exists, returns its context, otherwise returns the context of
+ * the parent ContextTree.
+ *
+ * This is required to always return a context which contains the all the imports
+ * declared up to `pos` (see SI-7280 for a test case).
+ *
+ * Can return None if `pos` is before any valid Scala code.
*/
def locateContext(contexts: Contexts, pos: Position): Option[Context] = synchronized {
- def locateNearestContextTree(contexts: Contexts, pos: Position, recent: Array[ContextTree]): Option[ContextTree] = {
- locateContextTree(contexts, pos) match {
- case Some(x) =>
- recent(0) = x
- locateNearestContextTree(x.children, pos, recent)
- case None => recent(0) match {
- case null => None
- case x => Some(x)
- }
+ @tailrec
+ def locateFinestContextTree(context: ContextTree): ContextTree = {
+ if (context.pos includes pos) {
+ locateContextTree(context.children, pos) match {
+ case Some(x) =>
+ locateFinestContextTree(x)
+ case None =>
+ context
+ }
+ } else {
+ context
}
}
- locateNearestContextTree(contexts, pos, new Array[ContextTree](1)) map (_.context)
+ locateContextTree(contexts, pos) map locateFinestContextTree map (_.context)
}
+ /** Returns the ContextTree containing `pos`, or the ContextTree positioned just before `pos`,
+ * or None if `pos` is located before all ContextTrees.
+ */
def locateContextTree(contexts: Contexts, pos: Position): Option[ContextTree] = {
if (contexts.isEmpty) None
else {
- val hi = contexts.length - 1
- if ((contexts(hi).pos properlyPrecedes pos) || (pos properlyPrecedes contexts(0).pos)) None
- else {
- def loop(lo: Int, hi: Int): Option[ContextTree] = {
+ @tailrec
+ def loop(lo: Int, hi: Int, previousSibling: Option[ContextTree]): Option[ContextTree] = {
+ if (pos properlyPrecedes contexts(lo).pos)
+ previousSibling
+ else if (contexts(hi).pos properlyPrecedes pos)
+ Some(contexts(hi))
+ else {
val mid = (lo + hi) / 2
val midpos = contexts(mid).pos
- if ((pos precedes midpos) && (mid < hi))
- loop(lo, mid)
- else if ((midpos precedes pos) && (lo < mid))
- loop(mid, hi)
- else if (midpos includes pos)
+ if (midpos includes pos)
Some(contexts(mid))
- else if (contexts(mid+1).pos includes pos)
- Some(contexts(mid+1))
- else None
+ else if (midpos properlyPrecedes pos)
+ loop(mid + 1, hi, Some(contexts(mid)))
+ else
+ loop(lo, mid, previousSibling)
}
- loop(0, hi)
}
+ loop(0, contexts.length - 1, None)
}
}
diff --git a/test/files/presentation/scope-completion-import.check b/test/files/presentation/scope-completion-import.check
new file mode 100644
index 0000000000..d518b0c37a
--- /dev/null
+++ b/test/files/presentation/scope-completion-import.check
@@ -0,0 +1,141 @@
+reload: Completions.scala
+
+askScopeCompletion at Completions.scala(15,4)
+================================================================================
+[response] askScopeCompletion at (15,4)
+retrieved 10 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo
+def fCCC: Int
+def fOOO: Int
+object O
+val o: test.O.type
+================================================================================
+
+askScopeCompletion at Completions.scala(19,4)
+================================================================================
+[response] askScopeCompletion at (19,4)
+retrieved 9 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo
+def fCCC: Int
+def fOOO: Int
+object O
+================================================================================
+
+askScopeCompletion at Completions.scala(24,4)
+================================================================================
+[response] askScopeCompletion at (24,4)
+retrieved 9 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo
+def fCCC: Int
+object O
+val c: test.C
+================================================================================
+
+askScopeCompletion at Completions.scala(27,5)
+================================================================================
+[response] askScopeCompletion at (27,5)
+retrieved 8 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo
+object O
+val c: test.C
+================================================================================
+
+askScopeCompletion at Completions.scala(30,5)
+================================================================================
+[response] askScopeCompletion at (30,5)
+retrieved 9 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo
+def fCCC: Int
+object O
+val c: test.C
+================================================================================
+
+askScopeCompletion at Completions.scala(32,5)
+================================================================================
+[response] askScopeCompletion at (32,5)
+retrieved 10 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo
+def fCCC: Int
+def fOOO: Int
+object O
+val c: test.C
+================================================================================
+
+askScopeCompletion at Completions.scala(41,4)
+================================================================================
+[response] askScopeCompletion at (41,4)
+retrieved 10 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo_1
+def bar: Unit
+def fCCC: Int
+def fOOO: Int
+object O
+================================================================================
+
+askScopeCompletion at Completions.scala(51,4)
+================================================================================
+[response] askScopeCompletion at (51,4)
+retrieved 11 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo_2
+def bar: Unit
+def fCCC: Int
+def fOOO: Int
+object O
+private[this] val o: test.O.type
+================================================================================
+
+askScopeCompletion at Completions.scala(61,4)
+================================================================================
+[response] askScopeCompletion at (61,4)
+retrieved 10 members
+class C extends AnyRef
+class Foo extends AnyRef
+class Foo_1 extends AnyRef
+class Foo_2 extends AnyRef
+class Foo_3 extends AnyRef
+def <init>(): test.Foo_3
+def bar: Unit
+def fCCC: Int
+object O
+private[this] val c: test.C
+================================================================================
diff --git a/test/files/presentation/scope-completion-import/Test.scala b/test/files/presentation/scope-completion-import/Test.scala
new file mode 100644
index 0000000000..bec1131c4c
--- /dev/null
+++ b/test/files/presentation/scope-completion-import/Test.scala
@@ -0,0 +1,3 @@
+import scala.tools.nsc.interactive.tests.InteractiveTest
+
+object Test extends InteractiveTest \ No newline at end of file
diff --git a/test/files/presentation/scope-completion-import/src/Completions.scala b/test/files/presentation/scope-completion-import/src/Completions.scala
new file mode 100644
index 0000000000..6e08321283
--- /dev/null
+++ b/test/files/presentation/scope-completion-import/src/Completions.scala
@@ -0,0 +1,64 @@
+package test
+
+class C {
+ def fCCC : Int = 0
+}
+
+object O extends C {
+ def fOOO : Int = 0
+}
+
+class Foo {
+ {
+ val o = O
+ import o._
+ /*_*/
+ }
+ {
+ import O._
+ /*_*/
+ }
+ {
+ val c = new C
+ import c._
+ /*_*/
+ }
+ {
+ f/*_*/
+ val c = new C
+ import c._
+ f/*_*/
+ import O._
+ f/*_*/
+ }
+}
+
+class Foo_1 {
+
+ import O._
+
+ def bar {
+ /*_*/
+ }
+}
+
+class Foo_2 {
+
+ val o = O
+ import o._
+
+ def bar {
+ /*_*/
+ }
+}
+
+class Foo_3 {
+
+ val c = new C
+ import c._
+
+ def bar {
+ /*_*/
+ }
+}
+