From 596ef0e94b3b4ea1b43b5eba49c5af014067798d Mon Sep 17 00:00:00 2001 From: chrisJames Date: Thu, 12 Aug 2010 11:58:52 +0000 Subject: [Scaladoc] Improve the documentation of primary... [Scaladoc] Improve the documentation of primary constructor. Adds a @constructor for commenting the primary constructor. It also adds some comments for the primary constructor (@params, @deprecated) which are initialised in the class comment. Members that come from primary constructor parameters (val parameters or parameters of a case class) are listed as members with the comment given using the @param tag (closes #254, closes #577). Case class signature now begins by 'case class' instead of 'class'. Review by dubochet --- .../scala/tools/nsc/doc/html/HtmlPage.scala | 9 ++ .../scala/tools/nsc/doc/html/page/Template.scala | 8 +- .../scala/tools/nsc/doc/model/Entity.scala | 22 +--- .../scala/tools/nsc/doc/model/ModelFactory.scala | 11 +- .../tools/nsc/doc/model/comment/Comment.scala | 5 +- .../nsc/doc/model/comment/CommentFactory.scala | 114 +++++++++++++++++---- 6 files changed, 119 insertions(+), 50 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index 014dee3b20..47d7503534 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -223,8 +223,17 @@ abstract class HtmlPage { thisPage => def docEntityKindToString(ety: DocTemplateEntity) = if (ety.isTrait) "trait" + else if (ety.isCaseClass) "case class" else if (ety.isClass) "class" else if (ety.isObject) "object" else if (ety.isPackage) "package" else "class" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not + + /** Returns the _big image name corresponding to the DocTemplate Entity (upper left icon) */ + def docEntityKindToBigImage(ety: DocTemplateEntity) = + if (ety.isTrait) "trait_big.png" + else if (ety.isClass) "class_big.png" + else if (ety.isObject) "object_big.png" + else if (ety.isPackage) "package_big.png" + else "class_big.png" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not } diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 324b04a54f..a4c100884b 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -52,7 +52,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { }
- +

{ if (tpl.isRootPackage) "root package" else tpl.name }

@@ -210,8 +210,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
{ commentToHtml(mbr.comment) }
} ++ { val prs: List[ParameterEntity] = mbr match { - case cls: Class if cls.isCaseClass => - cls.typeParams ::: (cls.primaryConstructor map (_.valueParams.flatten)).toList.flatten + case cls: Class => cls.typeParams ::: cls.valueParams.flatten case trt: Trait => trt.typeParams case dfe: Def => dfe.typeParams ::: dfe.valueParams.flatten case ctr: Constructor => ctr.valueParams.flatten @@ -425,8 +424,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage { vlsss map { vlss => ({implicitCheck(vlss) ++ params0(vlss) }) } } mbr match { - case cls: Class if cls.isCaseClass && cls.primaryConstructor.isDefined => - paramsToHtml(cls.primaryConstructor.get.valueParams) + case cls: Class => paramsToHtml(cls.valueParams) case ctr: Constructor => paramsToHtml(ctr.valueParams) case dfe: Def => paramsToHtml(dfe.valueParams) case _ => NodeSeq.Empty diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index 395ff66f33..6d81b8271e 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -33,6 +33,7 @@ trait TemplateEntity extends Entity { def isClass: Boolean def isObject: Boolean def isDocTemplate: Boolean + def isCaseClass: Boolean def selfType : Option[TypeEntity] } trait NoDocTemplate extends TemplateEntity @@ -83,33 +84,16 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity { def abstractTypes: List[AbstractType] def aliasTypes: List[AliasType] def companion: Option[DocTemplateEntity] - // temporary implementation: to be removed - def findMember(str: String): Option[DocTemplateEntity] = { - val root = toRoot.last - val path = if (str.length > 0) str.split("\\.") else Array[String]() - var i = 0; - var found: DocTemplateEntity = root - while(i < path.length && found != null) { - found = found.members.find(_.name == path(i)) match { - case Some(doc:DocTemplateEntity) => doc - case _ => null - } - i += 1 - } - Option(found) - } } /** A ''documentable'' trait. */ -trait Trait extends DocTemplateEntity with HigherKinded { - def valueParams : List[List[ValueParam]] -} +trait Trait extends DocTemplateEntity with HigherKinded /** A ''documentable'' class. */ trait Class extends Trait with HigherKinded { def primaryConstructor: Option[Constructor] def constructors: List[Constructor] - def isCaseClass: Boolean + def valueParams: List[List[ValueParam]] } /** A ''documentable'' object. */ diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index f430b31c05..e36df22435 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -70,6 +70,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory def isTrait = sym.isTrait def isClass = sym.isClass && !sym.isTrait def isObject = sym.isModule && !sym.isPackage + def isCaseClass = sym.isClass && sym.hasFlag(Flags.CASE) def isRootPackage = false def selfType = if (sym.thisSym eq sym) None else Some(makeType(sym.thisSym.typeOfThis, this)) } @@ -354,18 +355,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory else if (bSym.isModule || (bSym.isAliasType && bSym.tpe.typeSymbol.isModule)) new DocTemplateImpl(bSym, minimumInTpl) with Object else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait)) - new DocTemplateImpl(bSym, minimumInTpl) with Trait { - def valueParams = - List(sym.constrParamAccessors map (makeValueParam(_, this))) - } + new DocTemplateImpl(bSym, minimumInTpl) with Trait else if (bSym.isClass || (bSym.isAliasType && bSym.tpe.typeSymbol.isClass)) new DocTemplateImpl(bSym, minimumInTpl) with Class { def valueParams = - List(sym.constrParamAccessors map (makeValueParam(_, this))) + // we don't want params on a class (non case class) signature + if (isCaseClass) List(sym.constrParamAccessors map (makeValueParam(_, this))) + else List.empty val constructors = members collect { case d: Constructor => d } def primaryConstructor = constructors find { _.isPrimary } - def isCaseClass = sym.isClass && sym.hasFlag(Flags.CASE) } else throw new Error("'" + bSym + "' that isn't a class, trait or object cannot be built as a documentable template") diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala index 2a463959e5..fceb93b7c6 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala @@ -19,7 +19,7 @@ abstract class Comment { def body: Body /** A shorter version of the body. Usually, this is the first sentence of the body. */ - def short: Inline + def short: Inline = body.summary getOrElse Text("") /** A list of authors. The empty list is used when no author is defined. */ def authors: List[Body] @@ -62,6 +62,9 @@ abstract class Comment { /** A usage example related to the entity. */ def example: List[Body] + /** A description for the primary constructor */ + def constructor: Option[Body] + override def toString = body.toString + "\n" + (authors map ("@author " + _.toString)).mkString("\n") + diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index 6fe1fe06a4..94406ad2f8 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -36,13 +36,89 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => if (commentCache isDefinedAt key) Some(commentCache(key)) else { // not reached for use-case comments + val c = defineComment(sym, inTpl) + if (c isDefined) commentCache += (sym, inTpl) -> c.get + c + } + } + + /* A comment is usualy created by the parser, however for some special cases we have to give + * some inTpl comments (parent class for example) to the comment of the symbol + * This function manages some of those cases : Param accessor and Primary constructor + */ + def defineComment(sym: global.Symbol, inTpl: => DocTemplateImpl):Option[Comment] = + //param accessor case + // We just need the @param argument, we put it into the body + if( sym.isParamAccessor && + inTpl.comment.isDefined && + inTpl.comment.get.valueParams.isDefinedAt(sym.encodedName)) { + val comContent = Some(inTpl.comment.get.valueParams(sym.encodedName)) + Some(createComment(body0=comContent)) + } + + // Primary constructor case + // We need some content of the class definition : @constructor for the body, + // @param and @deprecated, we can add some more if necessary + else if (sym.isPrimaryConstructor && inTpl.comment.isDefined ) { + val tplComment = inTpl.comment.get + // If there is nothing to put into the comment there is no need to create it + if(tplComment.constructor.isDefined || + tplComment.throws != Map.empty || + tplComment.valueParams != Map.empty || + tplComment.typeParams != Map.empty || + tplComment.deprecated.isDefined + ) + Some(createComment( body0 = tplComment.constructor, + throws0 = tplComment.throws, + valueParams0 = tplComment.valueParams, + typeParams0 = tplComment.typeParams, + deprecated0 = tplComment.deprecated + )) + else None + } + //other comment cases + // parse function will make the comment + else { val rawComment = global.expandedDocComment(sym, inTpl.sym).trim - if (rawComment == "") None else { + if (rawComment != "") { val c = parse(rawComment, global.docCommentPos(sym)) - commentCache += (sym, inTpl) -> c Some(c) } - } + else None + } + + /* Creates comments with necessary arguments */ + def createComment(body0: Option[Body] = None, + authors0: List[Body] = List.empty, + see0: List[Body] = List.empty, + result0: Option[Body] = None, + throws0: Map[String,Body] = Map.empty, + valueParams0: Map[String,Body] = Map.empty, + typeParams0: Map[String,Body] = Map.empty, + version0: Option[Body] = None, + since0: Option[Body] = None, + todo0: List[Body] = List.empty, + deprecated0: Option[Body] = None, + note0: List[Body] = List.empty, + example0: List[Body] = List.empty, + constructor0: Option[Body] = None + ):Comment = + new Comment{ + val body = if(body0 isDefined) body0.get else Body(Seq.empty) + val authors = authors0 + val see = see0 + val result = result0 + val throws = throws0 + val valueParams = valueParams0 + val typeParams = typeParams0 + val version = version0 + val since = since0 + val todo = todo0 + val deprecated = deprecated0 + val note = note0 + val example = example0 + val constructor = constructor0 + } protected val endOfText = '\u0003' @@ -235,22 +311,22 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => Map.empty[String, Body] ++ pairs } - val com = new Comment { - val body = parseWiki(docBody, pos) - val authors = allTags(SimpleTagKey("author")) - val see = allTags(SimpleTagKey("see")) - val result = oneTag(SimpleTagKey("return")) - val throws = allSymsOneTag(SimpleTagKey("throws")) - val valueParams = allSymsOneTag(SimpleTagKey("param")) - val typeParams = allSymsOneTag(SimpleTagKey("tparam")) - val version = oneTag(SimpleTagKey("version")) - val since = oneTag(SimpleTagKey("since")) - val todo = allTags(SimpleTagKey("todo")) - val deprecated = oneTag(SimpleTagKey("deprecated")) - val note = allTags(SimpleTagKey("note")) - val example = allTags(SimpleTagKey("example")) - val short = body.summary getOrElse Text("no summary matey") - } + val com = createComment ( + body0 = Some(parseWiki(docBody, pos)), + authors0 = allTags(SimpleTagKey("author")), + see0 = allTags(SimpleTagKey("see")), + result0 = oneTag(SimpleTagKey("return")), + throws0 = allSymsOneTag(SimpleTagKey("throws")), + valueParams0 = allSymsOneTag(SimpleTagKey("param")), + typeParams0 = allSymsOneTag(SimpleTagKey("tparam")), + version0 = oneTag(SimpleTagKey("version")), + since0 = oneTag(SimpleTagKey("since")), + todo0 = allTags(SimpleTagKey("todo")), + deprecated0 = oneTag(SimpleTagKey("deprecated")), + note0 = allTags(SimpleTagKey("note")), + example0 = allTags(SimpleTagKey("example")), + constructor0 = oneTag(SimpleTagKey("constructor")) + ) for ((key, _) <- bodyTags) reporter.warning(pos, "Tag '@" + key.name + "' is not recognised") -- cgit v1.2.3