summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-11-08 14:25:01 +0000
committerPaul Phillips <paulp@improving.org>2010-11-08 14:25:01 +0000
commit948f4228c1a279f49093dbc7dc042eea749c463d (patch)
tree851295427a1ce42d810005a2c945a76c345d7046
parent7f8ccd778d34016e6fb63b218524783da3916573 (diff)
downloadscala-948f4228c1a279f49093dbc7dc042eea749c463d.tar.gz
scala-948f4228c1a279f49093dbc7dc042eea749c463d.tar.bz2
scala-948f4228c1a279f49093dbc7dc042eea749c463d.zip
A bit of -Xshow-class / -Xshow-object which did...
A bit of -Xshow-class / -Xshow-object which didn't quite make the Global patch. Now type selections should do the right thing, e.g. scalac -Xshow-class Global#Run src/compiler/scala/tools/nsc/Global.scala will show you interesting things about Run. Or see the test case for even more thrills. No review.
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala60
-rw-r--r--test/files/run/global-showdef.check14
-rw-r--r--test/files/run/global-showdef.scala69
3 files changed, 128 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 60b43a3d17..f3d6b9f41d 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -973,25 +973,55 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
atPhase(phase.next) { currentRun.units foreach treePrinter.print }
}
- def showDef(name: Name) {
- val segments = name.toString split '.'
- val container = segments.init.foldLeft(definitions.RootClass: Symbol)(_.info member _)
- val target = if (name.isTypeName) newTypeName(segments.last) else newTermName(segments.last)
-
- // If the name as given resolves to an existing symbol, show that.
- // Otherwise we'll show every symbol in the current run with a matching name.
- val syms = (container.info member target) match {
- case NoSymbol => currentRun.symSource.keys filter (_.name == name) toList
- case sym => List(sym)
+ /** We resolve the class/object ambiguity by passing a type/term name.
+ */
+ def showDef(fullName: Name, ph: Phase = currentRun.typerPhase.next) = {
+ def phased[T](body: => T): T = atPhase(ph)(body)
+
+ def walker(sym: Symbol, n: Name) = sym.info member n
+ def walk(root: Symbol, segs: List[Name]) = phased(segs.foldLeft(root)(walker))
+ def defs(sym: Symbol) = phased(sym.info.members map (x => if (x.isTerm) x.defString else x.toString))
+ def bases(sym: Symbol) = phased(sym.info.baseClasses map (_.fullName))
+ def mkName(str: String, term: Boolean) =
+ if (term) newTermName(str)
+ else newTypeName(str)
+
+ def nameSegments(name: String): List[Name] = {
+ name.indexWhere(ch => ch == '.' || ch == '#') match {
+ // it's the last segment: the argument to showDef tells us whether type or term
+ case -1 => if (name == "") Nil else List(mkName(name, fullName.isTermName))
+ // otherwise, we can tell based on whether '#' or '.' is the following char.
+ case idx =>
+ val (id, div, rest) = (name take idx, name charAt idx, name drop (idx + 1))
+ mkName(id, div == '.') :: nameSegments(rest)
+ }
+ }
+
+ val syms = {
+ // creates a list of simple type and term names.
+ val segments = nameSegments(fullName.toString)
+
+ // make the type/term selections walking from the root.
+ walk(definitions.RootClass, segments) match {
+ // The name as given was not found, so we'll sift through every symbol in
+ // the run looking for plausible matches.
+ case NoSymbol => phased {
+ currentRun.symSource.keys.toList .
+ filter (_.simpleName == segments.head) .
+ map (sym => walk(sym, segments.tail)) .
+ filterNot (_ == NoSymbol)
+ }
+ // The name as given matched, so show only that.
+ case sym => List(sym)
+ }
}
syms foreach { sym =>
- val name = "\n<<-- " + sym.kindString + " " + sym.fullName + " -->>\n"
- val baseClasses = sym.info.baseClasses map (_.fullName) mkString ("Base classes:\n ", "\n ", "\n")
- val members = atPhase(currentRun.typerPhase.next)(sym.info.members map (_.defString))
- val memberStr = members.mkString("Members after phase typer:\n ", "\n ", "\n")
+ val name = phased("\n<<-- " + sym.kindString + " " + sym.fullName + " -->>\n")
+ val baseClasses = bases(sym).mkString("Base classes:\n ", "\n ", "\n")
+ val members = defs(sym).mkString("Members after phase typer:\n ", "\n ", "\n")
- inform(List(name, baseClasses, memberStr) mkString "\n")
+ inform(List(name, baseClasses, members) mkString "\n")
}
}
diff --git a/test/files/run/global-showdef.check b/test/files/run/global-showdef.check
new file mode 100644
index 0000000000..8f67253ced
--- /dev/null
+++ b/test/files/run/global-showdef.check
@@ -0,0 +1,14 @@
+<<-- class foo.bar.Bippy -->>
+ def showdefTestMemberClass1: Int
+<<-- type foo.bar.Bippy.BippyType -->>
+ def showdefTestMemberType1: Unit
+<<-- type foo.bar.Bippy.BippyType -->>
+ def showdefTestMemberType2: Unit
+<<-- class foo.bar.Bippy.Boppity -->>
+ def showdefTestMemberClass2: Int
+<<-- class foo.bar.Bippy.Boppity.Boo -->>
+ def showdefTestMemberClass3: Int
+<<-- object foo.bar.Bippy -->>
+ def showdefTestMemberObject2: java.lang.String
+<<-- object foo.bar.Bippy.Boppity.Boo -->>
+ def showdefTestMemberObject1: java.lang.String
diff --git a/test/files/run/global-showdef.scala b/test/files/run/global-showdef.scala
new file mode 100644
index 0000000000..0b34fc4548
--- /dev/null
+++ b/test/files/run/global-showdef.scala
@@ -0,0 +1,69 @@
+import scala.tools.nsc._
+import io.{ AbstractFile }
+import util.{ SourceFile, BatchSourceFile, stringFromStream }
+import scala.tools.nsc.reporters.ConsoleReporter
+
+object Test {
+ val src: SourceFile = new BatchSourceFile("src", """
+package foo.bar
+
+class Bippy {
+ type BippyType <: {
+ def showdefTestMemberType1: Unit
+ }
+
+ def showdefTestMemberClass1 = 5
+ class Boppity {
+ def showdefTestMemberClass2 = 5
+ class Boo {
+ def showdefTestMemberClass3 = 5
+ }
+ object Boo {
+ def showdefTestMemberObject1 = "abc"
+ }
+ }
+}
+
+object Bippy {
+ type BippyType <: {
+ def showdefTestMemberType2: Unit
+ }
+
+ def showdefTestMemberObject2 = "abc"
+}
+ """)
+
+ def mkCompiler(args: String*) = {
+ val settings = new Settings()
+ val command = new CompilerCommand("-usejavacp" :: args.toList, settings)
+
+ new Global(settings)
+ }
+
+ def slurp(body: => Unit): String = stringFromStream { stream =>
+ Console.withOut(stream) {
+ Console.withErr(stream) {
+ body
+ }
+ }
+ }
+ def lines(args: String*): List[String] = {
+ val output = slurp {
+ val compiler = mkCompiler(args: _*)
+ val run = new compiler.Run()
+ run.compileSources(List(src))
+ }
+ output split "\\n" toList
+ }
+ def showClass(name: String) = lines("-Xshow-class", name)
+ def showObject(name: String) = lines("-Xshow-object", name)
+
+ def show(xs: List[String]) = {
+ xs filter (x => (x contains "def showdefTestMember") || (x startsWith "<<-- ")) foreach println
+ }
+
+ def main(args: Array[String]) {
+ show(List("Bippy", "Bippy#BippyType", "Bippy.BippyType", "Bippy#Boppity", "Bippy#Boppity#Boo") flatMap showClass)
+ show(List("Bippy", "Bippy#Boppity#Boo") flatMap showObject)
+ }
+}