From 948f4228c1a279f49093dbc7dc042eea749c463d Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 8 Nov 2010 14:25:01 +0000 Subject: 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. --- src/compiler/scala/tools/nsc/Global.scala | 60 ++++++++++++++++++++------- test/files/run/global-showdef.check | 14 +++++++ test/files/run/global-showdef.scala | 69 +++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 test/files/run/global-showdef.check create mode 100644 test/files/run/global-showdef.scala 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) + } +} -- cgit v1.2.3