From 98108febce145b9f2842937d3ac4a9c1d24f6108 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Fri, 16 Dec 2011 21:18:38 +0100 Subject: Fixed "Definition Classes" in bug #5287 --- src/compiler/scala/tools/nsc/ast/DocComments.scala | 10 +- .../scala/tools/nsc/doc/model/ModelFactory.scala | 34 ++-- .../scala/tools/partest/nest/CompileManager.scala | 3 +- test/scaladoc/resources/SI_5054_q7.scala | 8 +- test/scaladoc/resources/SI_5287.scala | 17 ++ test/scaladoc/scala/html.flags | 1 + test/scaladoc/scala/html/HtmlFactoryTest.flags | 1 + test/scaladoc/scala/html/HtmlFactoryTest.scala | 183 +++++++++------------ 8 files changed, 129 insertions(+), 128 deletions(-) create mode 100644 test/scaladoc/resources/SI_5287.scala create mode 100644 test/scaladoc/scala/html.flags create mode 100644 test/scaladoc/scala/html/HtmlFactoryTest.flags diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 8d52a7bd2c..f9c818daf0 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -99,7 +99,7 @@ trait DocComments { self: Global => */ def useCases(sym: Symbol, site: Symbol): List[(Symbol, String, Position)] = { def getUseCases(dc: DocComment) = { - for (uc <- dc.useCases; defn <- uc.expandedDefs(site)) yield + for (uc <- dc.useCases; defn <- uc.expandedDefs(sym, site)) yield (defn, expandVariables(merge(cookedDocComment(sym), uc.comment.raw, defn), sym, site), uc.pos) @@ -346,7 +346,7 @@ trait DocComments { self: Global => var defined: List[Symbol] = List() // initialized by Typer var aliases: List[Symbol] = List() // initialized by Typer - def expandedDefs(site: Symbol): List[Symbol] = { + def expandedDefs(sym: Symbol, site: Symbol): List[Symbol] = { def select(site: Type, name: Name, orElse: => Type): Type = { val member = site.nonPrivateMember(name) @@ -424,8 +424,10 @@ trait DocComments { self: Global => } for (defn <- defined) yield { - defn.cloneSymbol.setFlag(Flags.SYNTHETIC).setInfo( - substAliases(defn.info).asSeenFrom(site.thisType, defn.owner)) + val useCase = defn.cloneSymbol + useCase.owner = sym.owner + useCase.flags = sym.flags + useCase.setFlag(Flags.SYNTHETIC).setInfo(substAliases(defn.info).asSeenFrom(site.thisType, sym.owner)) } } } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 1fe96ed447..7eb8c393f3 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -100,11 +100,15 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { if (inTpl == null) None else thisFactory.comment(sym, inTpl) override def inTemplate = inTpl override def toRoot: List[MemberImpl] = this :: inTpl.toRoot - def inDefinitionTemplates = - if (inTpl == null) - makeRootPackage.toList - else - makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) + def inDefinitionTemplates = this match { + case mb: NonTemplateMemberEntity if (mb.useCaseOf.isDefined) => + mb.useCaseOf.get.inDefinitionTemplates + case _ => + if (inTpl == null) + makeRootPackage.toList + else + makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) + } def visibility = { if (sym.isPrivateLocal) PrivateInInstance() else if (sym.isProtectedLocal) ProtectedInInstance() @@ -119,18 +123,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { else Public() } } - def flags = this match { - // workaround for uninitialized flags in use cases - see SI-5054 - case m: NonTemplateMemberEntity if (m.useCaseOf.isDefined) => - m.useCaseOf.get.flags - case _ => - val fgs = mutable.ListBuffer.empty[Paragraph] - if (sym.isImplicit) fgs += Paragraph(Text("implicit")) - if (sym.isSealed) fgs += Paragraph(Text("sealed")) - if (!sym.isTrait && (sym hasFlag Flags.ABSTRACT)) fgs += Paragraph(Text("abstract")) - if (!sym.isTrait && (sym hasFlag Flags.DEFERRED)) fgs += Paragraph(Text("abstract")) - if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) - fgs.toList + def flags = { + val fgs = mutable.ListBuffer.empty[Paragraph] + if (sym.isImplicit) fgs += Paragraph(Text("implicit")) + if (sym.isSealed) fgs += Paragraph(Text("sealed")) + if (!sym.isTrait && (sym hasFlag Flags.ABSTRACT)) fgs += Paragraph(Text("abstract")) + if (!sym.isTrait && (sym hasFlag Flags.DEFERRED)) fgs += Paragraph(Text("abstract")) + if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) + fgs.toList } def deprecation = if (sym.isDeprecated) diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index f4ebfb7e7d..68688ff949 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -75,7 +75,8 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { val logWriter = new FileWriter(log) // check whether there is a ".flags" file - val flagsFileName = "%s.flags" format (basename(log.getName) dropRight 4) // 4 is "-run" or similar + val logFile = basename(log.getName) + val flagsFileName = "%s.flags" format (logFile.substring(0, logFile.lastIndexOf("-"))) val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse "" val allOpts = fileManager.SCALAC_OPTS.toList ::: argString.split(' ').toList.filter(_.length > 0) val args = allOpts.toList diff --git a/test/scaladoc/resources/SI_5054_q7.scala b/test/scaladoc/resources/SI_5054_q7.scala index 26d4b5fcf4..1bd120e30c 100644 --- a/test/scaladoc/resources/SI_5054_q7.scala +++ b/test/scaladoc/resources/SI_5054_q7.scala @@ -6,17 +6,17 @@ trait SI_5054_q7 { * * @param lost a lost parameter * @return some integer - * @usecase def test(): Int + * @usecase def test1(): Int * * This takes the implicit value in scope. * - * Example: `test()` + * Example: `test1()` * - * @usecase def test(explicit: Int): Int + * @usecase def test2(explicit: Int): Int * * This takes the explicit value passed. * - * Example: `test(3)` + * Example: `test2(3)` */ def test(implicit lost: Int): Int } diff --git a/test/scaladoc/resources/SI_5287.scala b/test/scaladoc/resources/SI_5287.scala new file mode 100644 index 0000000000..141ab15325 --- /dev/null +++ b/test/scaladoc/resources/SI_5287.scala @@ -0,0 +1,17 @@ +trait SI_5287_A { + def method(implicit a: Int): Int = a +} + +trait SI_5287_B extends SI_5287_A { + override def method(implicit a: Int): Int = a + 1 +} + +trait SI_5287 extends SI_5287_B{ + /** + * Some explanation + * + * @usecase def method(): Int + * The usecase explanation + */ + override def method(implicit a: Int): Int = a + 3 +} \ No newline at end of file diff --git a/test/scaladoc/scala/html.flags b/test/scaladoc/scala/html.flags new file mode 100644 index 0000000000..b2264ec4f4 --- /dev/null +++ b/test/scaladoc/scala/html.flags @@ -0,0 +1 @@ +-encoding UTF-8 \ No newline at end of file diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.flags b/test/scaladoc/scala/html/HtmlFactoryTest.flags new file mode 100644 index 0000000000..b2264ec4f4 --- /dev/null +++ b/test/scaladoc/scala/html/HtmlFactoryTest.flags @@ -0,0 +1 @@ +-encoding UTF-8 \ No newline at end of file diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scala/html/HtmlFactoryTest.scala index d1bfbb023f..5b17affbf0 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.scala +++ b/test/scaladoc/scala/html/HtmlFactoryTest.scala @@ -21,6 +21,9 @@ object XMLUtil { } object Test extends Properties("HtmlFactory") { + + final val RESOURCES = "test/scaladoc/resources/" + import scala.tools.nsc.doc.{DocFactory, Settings} import scala.tools.nsc.doc.model.IndexModelFactory import scala.tools.nsc.doc.html.HtmlFactory @@ -47,7 +50,7 @@ object Test extends Properties("HtmlFactory") { def createTemplates(basename: String) = { val result = scala.collection.mutable.Map[String, scala.xml.NodeSeq]() - createFactory.makeUniverse(List("test/scaladoc/resources/"+basename)) match { + createFactory.makeUniverse(List(RESOURCES+basename)) match { case Some(universe) => { val index = IndexModelFactory.makeIndex(universe) (new HtmlFactory(universe, index)).writeTemplates((page) => { @@ -61,7 +64,7 @@ object Test extends Properties("HtmlFactory") { } def createReferenceIndex(basename: String) = { - createFactory.makeUniverse(List("test/scaladoc/resources/"+basename)) match { + createFactory.makeUniverse(List(RESOURCES+basename)) match { case Some(universe) => { val index = IndexModelFactory.makeIndex(universe) val pages = index.firstLetterIndex.map({ @@ -81,6 +84,52 @@ object Test extends Properties("HtmlFactory") { val html = scala.stripSuffix(".scala") + ".html" createTemplates(scala)(html) } + + /** + * See checkTextOnly(scalaFile: String, checks: List[String]) + */ + def checkText1(scalaFile: String, check: String, debug: Boolean = true): Boolean = checkText(scalaFile, List(check), debug) + + /** + * This tests the text without the markup - ex: + * + *

+ * + * implicit + * def + * + * + * test(): Int + * + *

+ * + * becomes: + * + * implicit def test(): Int + * + * and is required to contain the text in the given checks + * + * NOTE: Comparison is done ignoring all whitespace + */ + def checkText(scalaFile: String, checks: List[String], debug: Boolean = true): Boolean = { + val htmlFile = scalaFile.stripSuffix(".scala") + ".html" + val htmlText = createTemplates(scalaFile)(htmlFile).text.replace('→',' ').replaceAll("\\s+","") + var result = true + + for (check <- checks) { + val checkText = check.replace('→',' ').replaceAll("\\s+","") + val checkValue = htmlText.contains(checkText) + if (debug && (!checkValue)) { + Console.err.println("Check failed: ") + Console.err.println("HTML: " + htmlText) + Console.err.println("Check: " + checkText) + } + result &&= checkValue + } + + result + } + def shortComments(root: scala.xml.Node) = XMLUtil.stripGroup(root).descendant.flatMap { @@ -377,113 +426,43 @@ object Test extends Properties("HtmlFactory") { createTemplate("SI_4898.scala") true } - - // A piece of the signature - corresponding to the use case - def signature(no: Int, modifier: String) = (""" -
  • - -

    - - """ + modifier + """ - def - - - test(): Int - -

    -

    [use case] -

    -
  • """).replaceAll("\\s+", "") - property("Use cases should override their original members") = { - createTemplate("SI_5054_q1.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(1, "")) - case _ => false - } - } - - property("Use cases should keep their flags - final should not be lost") = { - createTemplate("SI_5054_q2.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(2, "final")) - case _ => false - } - } + property("Use cases should override their original members") = + checkText1("SI_5054_q1.scala", """def test(): Int""") && + !checkText1("SI_5054_q1.scala", """def test(implicit lost: Int): Int""") - property("Use cases should keep their flags - implicit should not be lost") = { - createTemplate("SI_5054_q3.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(3, "implicit")) - case _ => false - } - } - property("Use cases should keep their flags - real abstract should not be lost") = { - createTemplate("SI_5054_q4.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(4, "abstract")) - case _ => false - } - } - - property("Use cases should keep their flags - traits should not be affected") = { - createTemplate("SI_5054_q5.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(5, "")) - case _ => false - } - } - - property("Use cases should keep their flags - traits should not be affected") = { - createTemplate("SI_5054_q6.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(signature(6, "abstract")) - case _ => false - } - } + property("Use cases should keep their flags - final should not be lost") = + checkText1("SI_5054_q2.scala", """final def test(): Int""") - val useCaseExplanation = """ -
  • - -

    - - abstract - def - - - test(): Int - -

    -

    [use case] This takes the implicit value in scope.

    [use case]

    This takes the implicit value in scope.

    Example: test()

    returns

    some integer -

    -
  • - -

    - - abstract - def - - - test(explicit: Int): Int - -

    -

    [use case] This takes the explicit value passed.

    [use case]

    This takes the explicit value passed.

    Example: test(3)

    returns

    some integer -

    -
  • - """.replaceAll("\\s+","") - - property("Use case individual signature test") = { - createTemplate("SI_5054_q7.scala") match { - case node: scala.xml.Node => - node.toString.replaceAll("\\s+","").contains(useCaseExplanation) - case _ => false - } - } + property("Use cases should keep their flags - implicit should not be lost") = + checkText1("SI_5054_q3.scala", """implicit def test(): Int""") + + property("Use cases should keep their flags - real abstract should not be lost") = + checkText1("SI_5054_q4.scala", """abstract def test(): Int""") + + property("Use cases should keep their flags - traits should not be affected") = + checkText1("SI_5054_q5.scala", """def test(): Int""") + + property("Use cases should keep their flags - traits should not be affected") = + checkText1("SI_5054_q6.scala", """abstract def test(): Int""") + + property("Use case individual signature test") = + checkText("SI_5054_q7.scala", List( + """abstract def test2(explicit: Int): Int [use case] This takes the explicit value passed.""", + """abstract def test1(): Int [use case] This takes the implicit value in scope.""")) + + property("Display correct \"Definition classes\"") = + checkText1("SI_5287.scala", + """def method(): Int + [use case] The usecase explanation + [use case] The usecase explanation + Definition Classes SI_5287 SI_5287_B SI_5287_A""", debug=true) + // explanation appears twice, as small comment and full comment { val files = createTemplates("basic.scala") - println(files) + //println(files) property("class") = files.get("com/example/p1/Clazz.html") match { case Some(node: scala.xml.Node) => { -- cgit v1.2.3