summaryrefslogtreecommitdiff
path: root/src/interactive
diff options
context:
space:
mode:
Diffstat (limited to 'src/interactive')
-rw-r--r--src/interactive/scala/tools/nsc/interactive/CompilerControl.scala37
-rw-r--r--src/interactive/scala/tools/nsc/interactive/ContextTrees.scala64
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala13
-rw-r--r--src/interactive/scala/tools/nsc/interactive/REPL.scala55
-rw-r--r--src/interactive/scala/tools/nsc/interactive/ScratchPadMaker.scala201
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala2
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala19
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala43
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/core/TestMarker.scala4
9 files changed, 97 insertions, 341 deletions
diff --git a/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala b/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala
index d036a6e853..69cae24808 100644
--- a/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala
+++ b/src/interactive/scala/tools/nsc/interactive/CompilerControl.scala
@@ -62,17 +62,6 @@ trait CompilerControl { self: Global =>
def onUnitOf[T](source: SourceFile)(op: RichCompilationUnit => T): T =
op(unitOfFile.getOrElse(source.file, new RichCompilationUnit(source)))
- /** The compilation unit corresponding to a source file
- * if it does not yet exist create a new one atomically
- * Note: We want to get roid of this operation as it messes compiler invariants.
- */
- @deprecated("use getUnitOf(s) or onUnitOf(s) instead", "2.10.0")
- def unitOf(s: SourceFile): RichCompilationUnit = getOrCreateUnitOf(s)
-
- /** The compilation unit corresponding to a position */
- @deprecated("use getUnitOf(pos.source) or onUnitOf(pos.source) instead", "2.10.0")
- def unitOf(pos: Position): RichCompilationUnit = getOrCreateUnitOf(pos.source)
-
/** Removes the CompilationUnit corresponding to the given SourceFile
* from consideration for recompilation.
*/
@@ -229,18 +218,6 @@ trait CompilerControl { self: Global =>
def askParsedEntered(source: SourceFile, keepLoaded: Boolean, response: Response[Tree]) =
postWorkItem(new AskParsedEnteredItem(source, keepLoaded, response))
- /** Set sync var `response` to a pair consisting of
- * - the fully qualified name of the first top-level object definition in the file.
- * or "" if there are no object definitions.
- * - the text of the instrumented program which, when run,
- * prints its output and all defined values in a comment column.
- *
- * @param source The source file to be analyzed
- * @param response The response.
- */
- @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
- def askInstrumented(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) =
- postWorkItem(new AskInstrumentedItem(source, line, response))
/** Cancels current compiler run and start a fresh one where everything will be re-typechecked
* (but not re-loaded).
@@ -250,11 +227,6 @@ trait CompilerControl { self: Global =>
/** Tells the compile server to shutdown, and not to restart again */
def askShutdown() = scheduler raise ShutdownReq
- @deprecated("use parseTree(source) instead", "2.10.0") // deleted 2nd parameter, as this has to run on 2.8 also.
- def askParse(source: SourceFile, response: Response[Tree]) = respond(response) {
- parseTree(source)
- }
-
/** Returns parse tree for source `source`. No symbols are entered. Syntax errors are reported.
*
* This method is thread-safe and as such can safely run outside of the presentation
@@ -419,15 +391,6 @@ trait CompilerControl { self: Global =>
response raise new MissingResponse
}
- @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
- case class AskInstrumentedItem(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) extends WorkItem {
- def apply() = self.getInstrumented(source, line, response)
- override def toString = "getInstrumented "+source
-
- def raiseMissing() =
- response raise new MissingResponse
- }
-
/** A do-nothing work scheduler that responds immediately with MissingResponse.
*
* Used during compiler shutdown.
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/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala
index 2790b04136..441398e443 100644
--- a/src/interactive/scala/tools/nsc/interactive/Global.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Global.scala
@@ -101,7 +101,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
with CompilerControl
with ContextTrees
with RichCompilationUnits
- with ScratchPadMaker
with Picklers {
import definitions._
@@ -1178,18 +1177,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
}
}
- @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
- def getInstrumented(source: SourceFile, line: Int, response: Response[(String, Array[Char])]) {
- try {
- interruptsEnabled = false
- respond(response) {
- instrument(source, line)
- }
- } finally {
- interruptsEnabled = true
- }
- }
-
// ---------------- Helper classes ---------------------------
/** The typer run */
diff --git a/src/interactive/scala/tools/nsc/interactive/REPL.scala b/src/interactive/scala/tools/nsc/interactive/REPL.scala
index 33981771ec..8e9b0ceee0 100644
--- a/src/interactive/scala/tools/nsc/interactive/REPL.scala
+++ b/src/interactive/scala/tools/nsc/interactive/REPL.scala
@@ -9,7 +9,6 @@ package interactive
import scala.reflect.internal.util._
import scala.tools.nsc.reporters._
import scala.tools.nsc.io._
-import scala.tools.nsc.scratchpad.SourceInserter
import java.io.FileWriter
/** Interface of interactive compiler to a client such as an IDE
@@ -89,8 +88,6 @@ object REPL {
val completeResult = new Response[List[comp.Member]]
val typedResult = new Response[comp.Tree]
val structureResult = new Response[comp.Tree]
- @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
- val instrumentedResult = new Response[(String, Array[Char])]
def makePos(file: String, off1: String, off2: String) = {
val source = toSourceFile(file)
@@ -112,52 +109,6 @@ object REPL {
show(structureResult)
}
- /** Write instrumented source file to disk.
- * @param iFullName The full name of the first top-level object in source
- * @param iContents An Array[Char] containing the instrumented source
- * @return The name of the instrumented source file
- */
- @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
- def writeInstrumented(iFullName: String, suffix: String, iContents: Array[Char]): String = {
- val iSimpleName = iFullName drop ((iFullName lastIndexOf '.') + 1)
- val iSourceName = iSimpleName + suffix
- val ifile = new FileWriter(iSourceName)
- ifile.write(iContents)
- ifile.close()
- iSourceName
- }
-
- /** The method for implementing worksheet functionality.
- * @param arguments a file name, followed by optional command line arguments that are passed
- * to the compiler that processes the instrumented source.
- * @param line A line number that controls uop to which line results should be produced
- * If line = -1, results are produced for all expressions in the worksheet.
- * @return The generated file content containing original source in the left column
- * and outputs in the right column, or None if the presentation compiler
- * does not respond to askInstrumented.
- */
- @deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
- def instrument(arguments: List[String], line: Int): Option[(String, String)] = {
- val source = toSourceFile(arguments.head)
- // strip right hand side comment column and any trailing spaces from all lines
- val strippedContents = SourceInserter.stripRight(source.content)
- val strippedSource = new BatchSourceFile(source.file, strippedContents)
- println("stripped source = "+strippedSource+":"+strippedContents.mkString)
- comp.askReload(List(strippedSource), reloadResult)
- comp.askInstrumented(strippedSource, line, instrumentedResult)
- using(instrumentedResult) {
- case (iFullName, iContents) =>
- println(s"instrumented source $iFullName = ${iContents.mkString}")
- val iSourceName = writeInstrumented(iFullName, "$instrumented.scala", iContents)
- val sSourceName = writeInstrumented(iFullName, "$stripped.scala", strippedContents)
- (iSourceName, sSourceName)
-/*
- * val vdirOpt = compileInstrumented(iSourceName, arguments.tail)
- runInstrumented(vdirOpt, iFullName, strippedSource.content)
- */
- }
- }
-
loop { line =>
(line split " ").toList match {
case "reload" :: args =>
@@ -177,10 +128,6 @@ object REPL {
doComplete(makePos(file, off1, off2))
case List("complete", file, off1) =>
doComplete(makePos(file, off1, off1))
- case "instrument" :: arguments =>
- println(instrument(arguments, -1))
- case "instrumentTo" :: line :: arguments =>
- println(instrument(arguments, line.toInt))
case List("quit") =>
comp.askShutdown()
sys.exit(1)
@@ -195,8 +142,6 @@ object REPL {
| typeat <file> <pos>
| complete <file> <start-pos> <end-pos>
| compile <file> <pos>
- | instrument <file> <arg>*
- | instrumentTo <line-num> <file> <arg>*
| structure <file>
| quit
|""".stripMargin)
diff --git a/src/interactive/scala/tools/nsc/interactive/ScratchPadMaker.scala b/src/interactive/scala/tools/nsc/interactive/ScratchPadMaker.scala
deleted file mode 100644
index 2400b97d97..0000000000
--- a/src/interactive/scala/tools/nsc/interactive/ScratchPadMaker.scala
+++ /dev/null
@@ -1,201 +0,0 @@
-package scala
-package tools.nsc
-package interactive
-
-import scala.reflect.internal.util.{SourceFile, BatchSourceFile, RangePosition}
-import scala.collection.mutable.ArrayBuffer
-import scala.reflect.internal.Chars.{isLineBreakChar, isWhitespace}
-import ast.parser.Tokens._
-
-@deprecated("SI-6458: Instrumentation logic will be moved out of the compiler.","2.10.0")
-trait ScratchPadMaker { self: Global =>
-
- import definitions._
-
- private case class Patch(offset: Int, text: String)
-
- private class Patcher(contents: Array[Char], lex: LexicalStructure, endOffset: Int) extends Traverser {
- var objectName: String = ""
-
- private val patches = new ArrayBuffer[Patch]
- private val toPrint = new ArrayBuffer[String]
- private var skipped = 0
- private var resNum: Int = -1
-
- private def nextRes(): String = {
- resNum += 1
- "res$"+resNum
- }
-
- private def nameType(name: String, tpe: Type): String = {
- // if name ends in symbol character, add a space to separate it from the following ':'
- val pad = if (Character.isLetter(name.last) || Character.isDigit(name.last)) "" else " "
- name+pad+": "+tpe
- }
-
- private def nameType(sym: Symbol): String = nameType(sym.name.decoded, sym.tpe)
-
- private def literal(str: String) = "\"\"\""+str+"\"\"\""
-
- private val prologue = ";import scala.runtime.WorksheetSupport._; def main(args: Array[String])=$execute{"
-
- private val epilogue = "}"
-
- private def applyPendingPatches(offset: Int) = {
- if (skipped == 0) patches += Patch(offset, prologue)
- for (msg <- toPrint) patches += Patch(offset, ";System.out.println("+msg+")")
- toPrint.clear()
- }
-
- /** The position where to insert an instrumentation statement in front of given statement.
- * This is at the latest `stat.pos.start`. But in order not to mess with column numbers
- * in position we try to insert it at the end of the previous token instead.
- * Furthermore, `(' tokens have to be skipped because they do not show up
- * in statement range positions.
- */
- private def instrumentPos(start: Int): Int = {
- val (prevToken, prevStart, prevEnd) = lex.locate(start - 1)
- if (prevStart >= start) start
- else if (prevToken == LPAREN) instrumentPos(prevStart)
- else prevEnd
- }
-
- private def addSkip(stat: Tree): Unit = {
- val ipos = instrumentPos(stat.pos.start)
- if (stat.pos.start > skipped) applyPendingPatches(ipos)
- if (stat.pos.start >= endOffset)
- patches += Patch(ipos, ";$stop()")
- var end = stat.pos.end
- if (end > skipped) {
- while (end < contents.length && !isLineBreakChar(contents(end))) end += 1
- patches += Patch(ipos, ";$skip("+(end-skipped)+"); ")
- skipped = end
- }
- }
-
- private def addSandbox(expr: Tree) = {}
-// patches += (Patch(expr.pos.start, "sandbox("), Patch(expr.pos.end, ")"))
-
- private def resultString(prefix: String, expr: String) =
- literal(prefix + " = ") + " + $show(" + expr + ")"
-
- private def traverseStat(stat: Tree) =
- if (stat.pos.isInstanceOf[RangePosition]) {
- stat match {
- case ValDef(_, _, _, rhs) =>
- addSkip(stat)
- if (stat.symbol.isLazy)
- toPrint += literal(nameType(stat.symbol) + " = <lazy>")
- else if (!stat.symbol.isSynthetic) {
- addSandbox(rhs)
- toPrint += resultString(nameType(stat.symbol), stat.symbol.name.toString)
- }
- case DefDef(_, _, _, _, _, _) =>
- addSkip(stat)
- toPrint += literal(nameType(stat.symbol))
- case Annotated(_, arg) =>
- traverse(arg)
- case DocDef(_, defn) =>
- traverse(defn)
- case _ =>
- if (stat.isTerm) {
- addSkip(stat)
- if (stat.tpe.typeSymbol == UnitClass) {
- addSandbox(stat)
- } else {
- val resName = nextRes()
- val dispResName = resName filter ('$' != _)
- val offset = instrumentPos(stat.pos.start)
- patches += Patch(offset, "val " + resName + " = ")
- addSandbox(stat)
- toPrint += resultString(nameType(dispResName, stat.tpe), resName)
- }
- }
- }
- }
-
- override def traverse(tree: Tree): Unit = tree match {
- case PackageDef(_, _) =>
- super.traverse(tree)
- case ModuleDef(_, name, Template(_, _, body)) =>
- val topLevel = objectName.isEmpty
- if (topLevel) {
- objectName = tree.symbol.fullName
- body foreach traverseStat
- if (skipped != 0) { // don't issue prologue and epilogue if there are no instrumented statements
- applyPendingPatches(skipped)
- patches += Patch(skipped, epilogue)
- }
- }
- case _ =>
- }
-
- /** The patched text.
- * @require traverse is run first
- */
- def result: Array[Char] = {
- val reslen = contents.length + (patches map (_.text.length)).sum
- val res = Array.ofDim[Char](reslen)
- var lastOffset = 0
- var from = 0
- var to = 0
- for (Patch(offset, text) <- patches) {
- val delta = offset - lastOffset
- assert(delta >= 0)
- Array.copy(contents, from, res, to, delta)
- from += delta
- to += delta
- lastOffset = offset
- text.copyToArray(res, to)
- to += text.length
- }
- assert(contents.length - from == reslen - to)
- Array.copy(contents, from, res, to, contents.length - from)
- res
- }
- }
-
- class LexicalStructure(source: SourceFile) {
- val token = new ArrayBuffer[Int]
- val startOffset = new ArrayBuffer[Int]
- val endOffset = new ArrayBuffer[Int]
- private val scanner = new syntaxAnalyzer.UnitScanner(new CompilationUnit(source))
- scanner.init()
- while (scanner.token != EOF) {
- startOffset += scanner.offset
- token += scanner.token
- scanner.nextToken()
- endOffset += scanner.lastOffset
- }
-
- /** @return token that starts before or at offset, its startOffset, its endOffset
- */
- def locate(offset: Int): (Int, Int, Int) = {
- var lo = 0
- var hi = token.length - 1
- while (lo < hi) {
- val mid = (lo + hi + 1) / 2
- if (startOffset(mid) <= offset) lo = mid
- else hi = mid - 1
- }
- (token(lo), startOffset(lo), endOffset(lo))
- }
- }
-
- /** Compute an instrumented version of a sourcefile.
- * @param source The given sourcefile.
- * @param line The line up to which results should be printed, -1 = whole document.
- * @return A pair consisting of
- * - the fully qualified name of the first top-level object definition in the file.
- * or "" if there are no object definitions.
- * - the text of the instrumented program which, when run,
- * prints its output and all defined values in a comment column.
- */
- protected def instrument(source: SourceFile, line: Int): (String, Array[Char]) = {
- val tree = typedTree(source, forceReload = true)
- val endOffset = if (line < 0) source.length else source.lineToOffset(line + 1)
- val patcher = new Patcher(source.content, new LexicalStructure(source), endOffset)
- patcher.traverse(tree)
- (patcher.objectName, patcher.result)
- }
-}
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala b/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala
index f30d896fb7..2cb4f5fd4a 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala
@@ -61,7 +61,7 @@ abstract class InteractiveTest
* Override this member if you need to change the default set of executed test actions.
*/
protected lazy val testActions: ListBuffer[PresentationCompilerTestDef] = {
- ListBuffer(new CompletionAction(compiler), new TypeAction(compiler), new HyperlinkAction(compiler))
+ ListBuffer(new TypeCompletionAction(compiler), new ScopeCompletionAction(compiler), new TypeAction(compiler), new HyperlinkAction(compiler))
}
/** Add new presentation compiler actions to test. Presentation compiler's test
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala
index 8d446cbbf8..4f9df6808f 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/core/AskCommand.scala
@@ -42,7 +42,7 @@ trait AskParse extends AskCommand {
import compiler.Tree
/** `sources` need to be entirely parsed before running the test
- * (else commands such as `AskCompletionAt` may fail simply because
+ * (else commands such as `AskTypeCompletionAt` may fail simply because
* the source's AST is not yet loaded).
*/
def askParse(sources: Seq[SourceFile]) {
@@ -72,10 +72,10 @@ trait AskReload extends AskCommand {
}
/** Ask the presentation compiler for completion at a given position. */
-trait AskCompletionAt extends AskCommand {
+trait AskTypeCompletionAt extends AskCommand {
import compiler.Member
- private[tests] def askCompletionAt(pos: Position)(implicit reporter: Reporter): Response[List[Member]] = {
+ private[tests] def askTypeCompletionAt(pos: Position)(implicit reporter: Reporter): Response[List[Member]] = {
reporter.println("\naskTypeCompletion at " + pos.source.file.name + ((pos.line, pos.column)))
ask {
@@ -84,6 +84,19 @@ trait AskCompletionAt extends AskCommand {
}
}
+/** Ask the presentation compiler for scope completion at a given position. */
+trait AskScopeCompletionAt extends AskCommand {
+ import compiler.Member
+
+ private[tests] def askScopeCompletionAt(pos: Position)(implicit reporter: Reporter): Response[List[Member]] = {
+ reporter.println("\naskScopeCompletion at " + pos.source.file.name + ((pos.line, pos.column)))
+
+ ask {
+ compiler.askScopeCompletion(pos, _)
+ }
+ }
+}
+
/** Ask the presentation compiler for type info at a given position. */
trait AskTypeAt extends AskCommand {
import compiler.Tree
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
index e28bf20745..bc490d8d45 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
@@ -12,16 +12,16 @@ private[tests] trait CoreTestDefs
/** Ask the presentation compiler for completion at all locations
* (in all sources) where the defined `marker` is found. */
- class CompletionAction(override val compiler: Global)
+ class TypeCompletionAction(override val compiler: Global)
extends PresentationCompilerTestDef
- with AskCompletionAt {
+ with AskTypeCompletionAt {
override def runTest() {
- askAllSources(CompletionMarker) { pos =>
- askCompletionAt(pos)
+ askAllSources(TypeCompletionMarker) { pos =>
+ askTypeCompletionAt(pos)
} { (pos, members) =>
withResponseDelimiter {
- reporter.println("[response] askCompletionAt " + format(pos))
+ reporter.println("[response] askTypeCompletion at " + format(pos))
// we skip getClass because it changed signature between 1.5 and 1.6, so there is no
// universal check file that we can provide for this to work
reporter.println("retrieved %d members".format(members.size))
@@ -34,6 +34,37 @@ private[tests] trait CoreTestDefs
}
}
+ /** Ask the presentation compiler for completion at all locations
+ * (in all sources) where the defined `marker` is found. */
+ class ScopeCompletionAction(override val compiler: Global)
+ extends PresentationCompilerTestDef
+ with AskScopeCompletionAt {
+
+ override def runTest() {
+ askAllSources(ScopeCompletionMarker) { pos =>
+ askScopeCompletionAt(pos)
+ } { (pos, members) =>
+ withResponseDelimiter {
+ reporter.println("[response] askScopeCompletion at " + format(pos))
+ try {
+ // exclude members not from source (don't have position), for more focused and self contained tests.
+ def eligible(sym: compiler.Symbol) = sym.pos != compiler.NoPosition
+ val filtered = members.filter(member => eligible(member.sym))
+
+ reporter.println("retrieved %d members".format(filtered.size))
+ compiler ask { () =>
+ reporter.println(filtered.map(_.forceInfoString).sorted mkString "\n")
+ }
+ } catch {
+ case t: Throwable =>
+ t.printStackTrace()
+ }
+
+ }
+ }
+ }
+ }
+
/** Ask the presentation compiler for type info at all locations
* (in all sources) where the defined `marker` is found. */
class TypeAction(override val compiler: Global)
@@ -57,7 +88,7 @@ private[tests] trait CoreTestDefs
class HyperlinkAction(override val compiler: Global)
extends PresentationCompilerTestDef
with AskTypeAt
- with AskCompletionAt {
+ with AskTypeCompletionAt {
override def runTest() {
askAllSources(HyperlinkMarker) { pos =>
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/TestMarker.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/TestMarker.scala
index a5c228a549..3f9b40277c 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/core/TestMarker.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/core/TestMarker.scala
@@ -20,7 +20,9 @@ abstract case class TestMarker(marker: String) {
TestMarker.checkForDuplicate(this)
}
-object CompletionMarker extends TestMarker("/*!*/")
+object TypeCompletionMarker extends TestMarker("/*!*/")
+
+object ScopeCompletionMarker extends TestMarker("/*_*/")
object TypeMarker extends TestMarker("/*?*/")