summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-04-27 12:40:34 -0700
committerPaul Phillips <paulp@improving.org>2013-04-27 12:40:34 -0700
commit464c9fedd2e3339d3f858213067b07a5b9a28b93 (patch)
treee1cf85c2f9ae368121a91029339f74766505371d
parent0c5e2e8f577165ac622a93e0b407f272130f0f37 (diff)
parentc4d0fd9998d96843cd9704d5610a29ab752ecb14 (diff)
downloadscala-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.scala92
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--test/files/run/memberpos.check11
-rw-r--r--test/files/run/memberpos.scala39
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 }
+
+"""
+}