diff options
author | Paul Phillips <paulp@improving.org> | 2013-04-27 12:40:34 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-04-27 12:40:34 -0700 |
commit | 464c9fedd2e3339d3f858213067b07a5b9a28b93 (patch) | |
tree | e1cf85c2f9ae368121a91029339f74766505371d | |
parent | 0c5e2e8f577165ac622a93e0b407f272130f0f37 (diff) | |
parent | c4d0fd9998d96843cd9704d5610a29ab752ecb14 (diff) | |
download | scala-464c9fedd2e3339d3f858213067b07a5b9a28b93.tar.gz scala-464c9fedd2e3339d3f858213067b07a5b9a28b93.tar.bz2 scala-464c9fedd2e3339d3f858213067b07a5b9a28b93.zip |
Merge pull request #2421 from paulp/pr/print-method-positions
-Yshow-member-pos, print the positions of members.
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala | 92 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 1 | ||||
-rw-r--r-- | test/files/run/memberpos.check | 11 | ||||
-rw-r--r-- | test/files/run/memberpos.scala | 39 |
4 files changed, 131 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 80d70e6428..3a695c6f59 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -11,30 +11,98 @@ import javac._ /** An nsc sub-component. */ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with Scanners with JavaParsers with JavaScanners { + import global._ val phaseName = "parser" - def newPhase(prev: Phase): StdPhase = new ParserPhase(prev) - class ParserPhase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) { + abstract class MemberDefTraverser extends Traverser { + def onMember(defn: MemberDef): Unit + + private var depth: Int = 0 + private def lower[T](body: => T): T = { + depth += 1 + try body finally depth -= 1 + } + def currentDepth = depth + + /** Prune this tree and all trees beneath it. Can be overridden. */ + def prune(md: MemberDef): Boolean = ( + md.mods.isSynthetic + || md.mods.isParamAccessor + || nme.isConstructorName(md.name) + || (md.name containsName nme.ANON_CLASS_NAME) + ) + + override def traverse(t: Tree): Unit = t match { + case md: MemberDef if prune(md) => + case md @ PackageDef(_, stats) => traverseTrees(stats) + case md: ImplDef => onMember(md) ; lower(traverseTrees(md.impl.body)) + case md: ValOrDefDef => onMember(md) ; lower(traverse(md.rhs)) + case _ => super.traverse(t) + } + } + + class MemberPosReporter(unit: CompilationUnit) extends MemberDefTraverser { + private var outputFn: MemberDef => String = outputForScreen + val path = unit.source.file.path + + // If a single line, outputs the line; if it spans multiple lines + // outputs NN,NN with start and end lines, e.g. 15,25. + def outputPos(md: MemberDef): String = { + val pos = md.pos + val start = pos.focusStart.line + val end = pos.focusEnd.line + + if (start == end) "" + start else s"$start,$end" + } + def outputForSed(md: MemberDef): String = { + val pos_s = "%-12s" format outputPos(md) + "p" + s"$pos_s $path # ${md.keyword} ${md.name}" + } + def outputForScreen(md: MemberDef): String = { + val pos_s = "%-20s" format " " * currentDepth + outputPos(md) + s"$pos_s ${md.keyword} ${md.name}" + } + + def onMember(md: MemberDef) = println(outputFn(md)) + // It recognizes "sed" and "anything else". + def show(style: String) { + if (style == "sed") { + outputFn = outputForSed + traverse(unit.body) + } + else { + outputFn = outputForScreen + println(path) + traverse(unit.body) + } + println("") + } + } + + private def initialUnitBody(unit: CompilationUnit): Tree = { + if (unit.isJava) new JavaUnitParser(unit).parse() + else if (global.reporter.incompleteHandled) newUnitParser(unit).parse() + else newUnitParser(unit).smartParse() + } + + class ParserPhase(prev: Phase) extends StdPhase(prev) { override val checkable = false override val keepsTypeParams = false - def apply(unit: global.CompilationUnit) { - import global._ + def apply(unit: CompilationUnit) { informProgress("parsing " + unit) - // if the body is already filled in, do nothing + // if the body is already filled in, don't overwrite it // otherwise compileLate is going to overwrite bodies of synthetic source files - if (unit.body == EmptyTree) { - unit.body = - if (unit.isJava) new JavaUnitParser(unit).parse() - else if (reporter.incompleteHandled) newUnitParser(unit).parse() - else newUnitParser(unit).smartParse() - } + if (unit.body == EmptyTree) + unit.body = initialUnitBody(unit) if (settings.Yrangepos && !reporter.hasErrors) validatePositions(unit.body) + + if (settings.Ymemberpos.isSetByUser) + new MemberPosReporter(unit) show (style = settings.Ymemberpos.value) } } } - diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index ee9a3aed2a..a30f144802 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -164,6 +164,7 @@ trait ScalaSettings extends AbsScalaSettings val refinementMethodDispatch = ChoiceSetting ("-Ystruct-dispatch", "policy", "structural method dispatch policy", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.") + val Ymemberpos = StringSetting ("-Yshow-member-pos", "output style", "Show start and end positions of members", "") withPostSetHook (_ => Yrangepos.value = true) val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "") diff --git a/test/files/run/memberpos.check b/test/files/run/memberpos.check new file mode 100644 index 0000000000..e7d3534000 --- /dev/null +++ b/test/files/run/memberpos.check @@ -0,0 +1,11 @@ +newSource1 +2,4 class A +6,28 object A + 7,10 def bippy + 8 def hello + 11,27 class Dingo + 12,26 def foooooz + 22 val a +30 class B + 30 def f + diff --git a/test/files/run/memberpos.scala b/test/files/run/memberpos.scala new file mode 100644 index 0000000000..f2b79c0ec1 --- /dev/null +++ b/test/files/run/memberpos.scala @@ -0,0 +1,39 @@ +import scala.tools.partest._ + +// Simple sanity test for -Yshow-member-pos. +object Test extends DirectTest { + override def extraSettings: String = "-usejavacp -Ystop-after:parser -Yshow-member-pos \"\" -d " + testOutput.path + override def show() = compile() + override def code = """ +class A(val a: Int = 1) { + +} + +object A { + def bippy = { + def hello = 55 + "" + hello + } + class Dingo { + def foooooz = /**** + + + + + + ****/ { + + + + val a = 1 + + + a + } + } +} + +class B { def f = 1 } + +""" +} |