diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 15 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaScanners.scala | 38 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 7 | ||||
-rw-r--r-- | src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala | 119 | ||||
-rw-r--r-- | src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala | 3 | ||||
-rw-r--r-- | src/scaladoc/scala/tools/partest/ScaladocModelTest.scala | 2 | ||||
-rw-r--r-- | test/files/run/t5699.check | 4 | ||||
-rw-r--r-- | test/scaladoc/resources/SI-4826.java | 20 | ||||
-rw-r--r-- | test/scaladoc/run/SI-4826.check | 1 | ||||
-rw-r--r-- | test/scaladoc/run/SI-4826.scala | 30 |
12 files changed, 171 insertions, 74 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 9d6693c00f..d4c2896c5c 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -411,7 +411,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) override val initial = true } - import syntaxAnalyzer.{ UnitScanner, UnitParser } + import syntaxAnalyzer.{ UnitScanner, UnitParser, JavaUnitParser } // !!! I think we're overdue for all these phase objects being lazy vals. // There's no way for a Global subclass to provide a custom typer @@ -1042,6 +1042,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def newUnitParser(code: String, filename: String = "<console>"): UnitParser = newUnitParser(newCompilationUnit(code, filename)) + def newJavaUnitParser(unit: CompilationUnit): JavaUnitParser = new JavaUnitParser(unit) + /** A Run is a single execution of the compiler on a set of units. */ class Run extends RunContextApi with RunReporting with RunParsing { diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index df2073785b..e0667b5a3e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -82,7 +82,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse } private def initialUnitBody(unit: CompilationUnit): Tree = { - if (unit.isJava) new JavaUnitParser(unit).parse() + if (unit.isJava) newJavaUnitParser(unit).parse() else if (currentRun.parsing.incompleteHandled) newUnitParser(unit).parse() else newUnitParser(unit).smartParse() } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index fd9c99a3b9..01ca8033ac 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -111,7 +111,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def arrayOf(tpt: Tree) = AppliedTypeTree(scalaDot(tpnme.Array), List(tpt)) - def blankExpr = Ident(nme.WILDCARD) + def blankExpr = EmptyTree def makePackaging(pkg: RefTree, stats: List[Tree]): PackageDef = atPos(pkg.pos) { PackageDef(pkg, stats) } @@ -135,6 +135,11 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { DefDef(Modifiers(Flags.JAVA), nme.CONSTRUCTOR, List(), List(vparams), TypeTree(), blankExpr) } + /** A hook for joining the comment associated with a definition. + * Overridden by scaladoc. + */ + def joinComment(trees: => List[Tree]): List[Tree] = trees + // ------------- general parsing --------------------------- /** skip parent or brace enclosed sequence of things */ @@ -581,7 +586,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { case CLASS | ENUM | INTERFACE | AT => typeDecl(if (definesInterface(parentToken)) mods | Flags.STATIC else mods) case _ => - termDecl(mods, parentToken) + joinComment(termDecl(mods, parentToken)) } def makeCompanionObject(cdef: ClassDef, statics: List[Tree]): Tree = @@ -833,10 +838,10 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { } def typeDecl(mods: Modifiers): List[Tree] = in.token match { - case ENUM => enumDecl(mods) - case INTERFACE => interfaceDecl(mods) + case ENUM => joinComment(enumDecl(mods)) + case INTERFACE => joinComment(interfaceDecl(mods)) case AT => annotationDecl(mods) - case CLASS => classDecl(mods) + case CLASS => joinComment(classDecl(mods)) case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree) } diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index c74a6938c6..e11ac94041 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -577,21 +577,29 @@ trait JavaScanners extends ast.parser.ScannersCommon { } } - protected def skipComment(): Boolean = { - @tailrec def skipLineComment(): Unit = in.ch match { - case CR | LF | SU => - case _ => in.next; skipLineComment() - } - @tailrec def skipJavaComment(): Unit = in.ch match { - case SU => incompleteInputError("unclosed comment") - case '*' => in.next; if (in.ch == '/') in.next else skipJavaComment() - case _ => in.next; skipJavaComment() - } - in.ch match { - case '/' => in.next ; skipLineComment() ; true - case '*' => in.next ; skipJavaComment() ; true - case _ => false - } + protected def putCommentChar(): Unit = in.next() + + protected def skipBlockComment(isDoc: Boolean): Unit = in.ch match { + case SU => incompleteInputError("unclosed comment") + case '*' => putCommentChar() ; if (in.ch == '/') putCommentChar() else skipBlockComment(isDoc) + case _ => putCommentChar() ; skipBlockComment(isDoc) + } + + protected def skipLineComment(): Unit = in.ch match { + case CR | LF | SU => + case _ => putCommentChar() ; skipLineComment() + } + + protected def skipComment(): Boolean = in.ch match { + case '/' => putCommentChar() ; skipLineComment() ; true + case '*' => + putCommentChar() + in.ch match { + case '*' => skipBlockComment(isDoc = true) + case _ => skipBlockComment(isDoc = false) + } + true + case _ => false } // Identifiers --------------------------------------------------------------- diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9fa3564b2b..ba104fb7a6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2247,9 +2247,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe) } - if (meth.isClassConstructor && !isPastTyper && !meth.owner.isSubClass(AnyValClass)) { - // At this point in AnyVal there is no supercall, which will blow up - // in computeParamAliases; there's nothing to be computed for Anyval anyway. + if (meth.isClassConstructor && !isPastTyper && !meth.owner.isSubClass(AnyValClass) && !meth.isJava) { + // There are no supercalls for AnyVal or constructors from Java sources, which + // would blow up in computeParamAliases; there's nothing to be computed for them + // anyway. if (meth.isPrimaryConstructor) computeParamAliases(meth.owner, vparamss1, rhs1) else diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala index 8ea8c4deff..2152ce234a 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala @@ -101,52 +101,6 @@ trait ScaladocAnalyzer extends Analyzer { abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends SyntaxAnalyzer { import global._ - class ScaladocJavaUnitParser(unit: CompilationUnit) extends { - override val in = new ScaladocJavaUnitScanner(unit) - } with JavaUnitParser(unit) { } - - class ScaladocJavaUnitScanner(unit: CompilationUnit) extends JavaUnitScanner(unit) { - /** buffer for the documentation comment - */ - var docBuffer: StringBuilder = null - - /** add the given character to the documentation buffer - */ - protected def putDocChar(c: Char) { - if (docBuffer ne null) docBuffer.append(c) - } - - override protected def skipComment(): Boolean = { - if (in.ch == '/') { - do { - in.next - } while ((in.ch != CR) && (in.ch != LF) && (in.ch != SU)) - true - } else if (in.ch == '*') { - docBuffer = null - in.next - val scaladoc = ("/**", "*/") - if (in.ch == '*') - docBuffer = new StringBuilder(scaladoc._1) - do { - do { - if (in.ch != '*' && in.ch != SU) { - in.next; putDocChar(in.ch) - } - } while (in.ch != '*' && in.ch != SU) - while (in.ch == '*') { - in.next; putDocChar(in.ch) - } - } while (in.ch != '/' && in.ch != SU) - if (in.ch == '/') in.next - else incompleteInputError("unclosed comment") - true - } else { - false - } - } - } - class ScaladocUnitScanner(unit0: CompilationUnit, patches0: List[BracePatch]) extends UnitScanner(unit0, patches0) { private var docBuffer: StringBuilder = null // buffer for comments (non-null while scanning) @@ -259,4 +213,77 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax else trees } } + + class ScaladocJavaUnitScanner(unit: CompilationUnit) extends JavaUnitScanner(unit) { + + private val docBuffer: StringBuilder = new StringBuilder + private var inDocComment = false + private var docStart: Int = 0 + private var lastDoc: DocComment = null + + // get last doc comment + def flushDoc(): DocComment = try lastDoc finally lastDoc = null + + override protected def putCommentChar(): Unit = { + if (inDocComment) docBuffer append in.ch + in.next + } + + override protected def skipBlockComment(isDoc: Boolean): Unit = { + // condition is true when comment is entered the first time, + // i.e. immediately after "/*" and when current character is "*" + if (!inDocComment && isDoc) { + docBuffer append "/*" + docStart = currentPos.start + inDocComment = true + } + super.skipBlockComment(isDoc) + } + + override protected def skipComment(): Boolean = { + val skipped = super.skipComment() + if (skipped && inDocComment) { + val raw = docBuffer.toString + val position = Position.range(unit.source, docStart, docStart, in.cpos) + lastDoc = DocComment(raw, position) + signalParsedDocComment(raw, position) + docBuffer.setLength(0) // clear buffer + inDocComment = false + true + } else { + skipped + } + } + + } + + class ScaladocJavaUnitParser(unit: CompilationUnit) extends { + override val in = new ScaladocJavaUnitScanner(unit) + } with JavaUnitParser(unit) { + + override def joinComment(trees: => List[Tree]): List[Tree] = { + val doc = in.flushDoc() + + if ((doc ne null) && doc.raw.length > 0) { + log(s"joinComment(doc=$doc)") + val joined = trees map { t => + DocDef(doc, t) setPos { + if (t.pos.isDefined) { + val pos = doc.pos.withEnd(t.pos.end) + pos.makeTransparent + } else { + t.pos + } + } + } + joined.find(_.pos.isOpaqueRange) foreach { main => + val mains = List(main) + joined foreach { t => if (t ne main) ensureNonOverlapping(t, mains) } + } + joined + } else { + trees + } + } + } } diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala index 10bfe6f94b..625d074df5 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala @@ -13,6 +13,7 @@ trait ScaladocGlobalTrait extends Global { override val useOffsetPositions = false override def newUnitParser(unit: CompilationUnit) = new syntaxAnalyzer.ScaladocUnitParser(unit, Nil) + override def newJavaUnitParser(unit: CompilationUnit) = new syntaxAnalyzer.ScaladocJavaUnitParser(unit) override lazy val syntaxAnalyzer = new ScaladocSyntaxAnalyzer[outer.type](outer) { val runsAfter = List[String]() @@ -40,6 +41,8 @@ class ScaladocGlobal(settings: doc.Settings, reporter: Reporter) extends Global( phasesSet += analyzer.typerFactory } override def forScaladoc = true + override def createJavadoc = true + override lazy val analyzer = new { val global: ScaladocGlobal.this.type = ScaladocGlobal.this } with ScaladocAnalyzer diff --git a/src/scaladoc/scala/tools/partest/ScaladocModelTest.scala b/src/scaladoc/scala/tools/partest/ScaladocModelTest.scala index 1ad3b3ff2b..44c1146a14 100644 --- a/src/scaladoc/scala/tools/partest/ScaladocModelTest.scala +++ b/src/scaladoc/scala/tools/partest/ScaladocModelTest.scala @@ -81,7 +81,7 @@ abstract class ScaladocModelTest extends DirectTest { private[this] var settings: doc.Settings = null // create a new scaladoc compiler - private[this] def newDocFactory: DocFactory = { + def newDocFactory: DocFactory = { settings = new doc.Settings(_ => ()) settings.scaladocQuietRun = true // yaay, no more "model contains X documentable templates"! val args = extraSettings + " " + scaladocSettings diff --git a/test/files/run/t5699.check b/test/files/run/t5699.check index df19644ae6..8d19ecd321 100644 --- a/test/files/run/t5699.check +++ b/test/files/run/t5699.check @@ -1,10 +1,10 @@ [[syntax trees at end of parser]] // annodef.java package <empty> { object MyAnnotation extends { - def <init>() = _ + def <init>() }; class MyAnnotation extends scala.annotation.Annotation with _root_.java.lang.annotation.Annotation with scala.annotation.ClassfileAnnotation { - def <init>() = _; + def <init>(); def value(): String } } diff --git a/test/scaladoc/resources/SI-4826.java b/test/scaladoc/resources/SI-4826.java new file mode 100644 index 0000000000..f735ce6335 --- /dev/null +++ b/test/scaladoc/resources/SI-4826.java @@ -0,0 +1,20 @@ +package test.scaladoc; + +/** + * Testing java comments. The presence of a :marker: + * tag is verified by tests. + */ +public class JavaComments { + + /** + * Compute the answer to the ultimate question of life, the + * universe, and everything. :marker: + * @param factor scaling factor to the answer + * @return the answer to everything (42) scaled by factor + */ + public int answer(int factor) { + return 42 * factor; + } + +} + diff --git a/test/scaladoc/run/SI-4826.check b/test/scaladoc/run/SI-4826.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/SI-4826.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/SI-4826.scala b/test/scaladoc/run/SI-4826.scala new file mode 100644 index 0000000000..50e4468002 --- /dev/null +++ b/test/scaladoc/run/SI-4826.scala @@ -0,0 +1,30 @@ +import scala.tools.nsc.doc.Universe +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def resourceFile = "SI-4826.java" + + // overridden to pass explicit files to newDocFactory.makeUniverse (rather than code strings) + // since the .java file extension is required + override def model: Option[Universe] = { + val path = resourcePath + "/" + resourceFile + newDocFactory.makeUniverse(Left(List(path))) + } + + // no need for special settings + def scaladocSettings = "" + + def testModel(rootPackage: Package) = { + import access._ + val Tag = ":marker:" + + val base = rootPackage._package("test")._package("scaladoc") + val clazz = base._class("JavaComments") + val method = clazz._method("answer") + + assert(extractCommentText(clazz.comment.get).contains(Tag)) + assert(extractCommentText(method.comment.get).contains(Tag)) + } +} |