Skip to content

Commit

Permalink
[scaladoc] Annotations are modeled and printed.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilles Dubochet committed Nov 5, 2010
1 parent e3b2ebc commit 4659d81
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 32 deletions.
80 changes: 53 additions & 27 deletions src/compiler/scala/tools/nsc/doc/html/page/Template.scala
Expand Up @@ -219,7 +219,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
<p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p> <p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p>


def memberToCommentBodyHtml(mbr: MemberEntity, isSelf: Boolean, isReduced: Boolean = false): NodeSeq = def memberToCommentBodyHtml(mbr: MemberEntity, isSelf: Boolean, isReduced: Boolean = false): NodeSeq = {
NodeSeq.Empty ++ NodeSeq.Empty ++
{ if (mbr.comment.isEmpty) NodeSeq.Empty else { if (mbr.comment.isEmpty) NodeSeq.Empty else
<div class="comment cmt">{ commentToHtml(mbr.comment) }</div> <div class="comment cmt">{ commentToHtml(mbr.comment) }</div>
Expand Down Expand Up @@ -310,6 +310,30 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
case _ => NodeSeq.Empty case _ => NodeSeq.Empty
} }
} ++ } ++
{ if (!mbr.annotations.isEmpty) {
<div class="block">
annotations: {
mbr.annotations.map { annot =>
<xml:group>
<span class="name">@{ templateToHtml(annot.annotationClass) }</span>{
def paramsToHtml(vls: List[ValueArgument]): NodeSeq =
vls map { vl =>
<span>{
vl.parameter match {
case Some(p) => Text(p.name + " = ")
case None => NodeSeq.Empty
}
}{ treeToHtml(vl.value) }</span>
}
<span class="params">({ paramsToHtml(annot.arguments) })</span>
}
</xml:group>
}
}
</div>
}
else NodeSeq.Empty
} ++
{ mbr match { { mbr match {
case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) => case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) =>
val (absFile, line) = dtpl.inSource.get val (absFile, line) = dtpl.inSource.get
Expand Down Expand Up @@ -351,6 +375,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
case None => NodeSeq.Empty case None => NodeSeq.Empty
} }
} }
}


def kindToString(mbr: MemberEntity): String = mbr match { def kindToString(mbr: MemberEntity): String = mbr match {
case tpl: DocTemplateEntity => docEntityKindToString(tpl) case tpl: DocTemplateEntity => docEntityKindToString(tpl)
Expand Down Expand Up @@ -418,33 +443,35 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
tparamsToHtml(mbr) tparamsToHtml(mbr)
} }
{ if (isReduced) NodeSeq.Empty else { { if (isReduced) NodeSeq.Empty else {
def paramsToHtml(vlsss: List[List[ValueParam]]): NodeSeq = { def paramsToHtml(vlsss: List[List[ValueParam]]): NodeSeq = {
def param0(vl: ValueParam): NodeSeq = def param0(vl: ValueParam): NodeSeq =
// notice the }{ in the next lines, they are necessary to avoid a undesired withspace in output // notice the }{ in the next lines, they are necessary to avoid a undesired withspace in output
<span name={ vl.name }>{ Text(vl.name + ": ") }{ typeToHtml(vl.resultType, hasLinks) }{ <span name={ vl.name }>{ Text(vl.name + ": ") }{ typeToHtml(vl.resultType, hasLinks) }{
if(!vl.defaultValue.isEmpty) { if(!vl.defaultValue.isEmpty) {
defaultValueToHtml(vl.defaultValue.get); treeToHtml(vl.defaultValue.get);
} }
else NodeSeq.Empty else NodeSeq.Empty
}</span> }</span>
def params0(vlss: List[ValueParam]): NodeSeq = vlss match {
case Nil => NodeSeq.Empty def params0(vlss: List[ValueParam]): NodeSeq = vlss match {
case vl :: Nil => param0(vl) case Nil => NodeSeq.Empty
case vl :: vls => param0(vl) ++ Text(", ") ++ params0(vls) case vl :: Nil => param0(vl)
case vl :: vls => param0(vl) ++ Text(", ") ++ params0(vls)
}
def implicitCheck(vlss: List[ValueParam]): NodeSeq = vlss match {
case vl :: vls => if(vl.isImplicit) { <span class="implicit">implicit </span> } else Text("")
case _ => Text("")
}
vlsss map { vlss => <span class="params">({implicitCheck(vlss) ++ params0(vlss) })</span> }
} }
def implicitCheck(vlss: List[ValueParam]): NodeSeq = vlss match { mbr match {
case vl :: vls => if(vl.isImplicit) { <span class="implicit">implicit </span> } else Text("") case cls: Class => paramsToHtml(cls.valueParams)
case _ => Text("") case ctr: Constructor => paramsToHtml(ctr.valueParams)
case dfe: Def => paramsToHtml(dfe.valueParams)
case _ => NodeSeq.Empty
} }
vlsss map { vlss => <span class="params">({implicitCheck(vlss) ++ params0(vlss) })</span> }
} }
mbr match { }
case cls: Class => paramsToHtml(cls.valueParams)
case ctr: Constructor => paramsToHtml(ctr.valueParams)
case dfe: Def => paramsToHtml(dfe.valueParams)
case _ => NodeSeq.Empty
}
}}
{ if (isReduced) NodeSeq.Empty else { { if (isReduced) NodeSeq.Empty else {
mbr match { mbr match {
case tpl: DocTemplateEntity if (!tpl.isPackage) => case tpl: DocTemplateEntity if (!tpl.isPackage) =>
Expand Down Expand Up @@ -477,7 +504,7 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
} }


/** */ /** */
def defaultValueToHtml(defVal:TreeEntity):NodeSeq = { def treeToHtml(defVal:TreeEntity):NodeSeq = {
var index = 0 var index = 0
val str = defVal.expression val str = defVal.expression
val length = str.length val length = str.length
Expand All @@ -500,7 +527,6 @@ class Template(tpl: DocTemplateEntity) extends HtmlPage {
val anchor = "#" + mbr.name + defParamsString(mbr) + ":" + mbr.resultType.name val anchor = "#" + mbr.name + defParamsString(mbr) + ":" + mbr.resultType.name
val link = relativeLinkTo(mbr.inTemplate) val link = relativeLinkTo(mbr.inTemplate)
myXml ++= <span class="name"><a href={link ++ anchor}>{str.substring(from, to)}</a></span> myXml ++= <span class="name"><a href={link ++ anchor}>{str.substring(from, to)}</a></span>
case _ => assert(false, "unexpected case in defaultValueToHtml")
} }
index = to index = to
} }
Expand Down
13 changes: 13 additions & 0 deletions src/compiler/scala/tools/nsc/doc/model/Entity.scala
Expand Up @@ -18,6 +18,7 @@ trait Entity {
def qualifiedName: String def qualifiedName: String
override def toString = qualifiedName override def toString = qualifiedName
def universe: Universe def universe: Universe
def annotations: List[Annotation]
} }


/** A class, trait, object or package. A package is represented as an instance /** A class, trait, object or package. A package is represented as an instance
Expand Down Expand Up @@ -158,6 +159,18 @@ trait ValueParam extends ParameterEntity {
def isImplicit: Boolean def isImplicit: Boolean
} }


/** An annotation, defined by its class and its constructor arguments. */
trait Annotation extends Entity {
def annotationClass: TemplateEntity
def arguments: List[ValueArgument]
}

/** A value that is passed as an argument to a value paramater. */
trait ValueArgument {
def parameter: Option[ValueParam]
def value: TreeEntity
}

/** An type that represents visibility of members. */ /** An type that represents visibility of members. */
sealed trait Visibility { sealed trait Visibility {
def isProtected: Boolean = false def isProtected: Boolean = false
Expand Down
40 changes: 36 additions & 4 deletions src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
Expand Up @@ -59,6 +59,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def toRoot: List[EntityImpl] = this :: inTpl.toRoot def toRoot: List[EntityImpl] = this :: inTpl.toRoot
def qualifiedName = name def qualifiedName = name
val universe = thisFactory.universe val universe = thisFactory.universe
def annotations = sym.annotations.map(makeAnnotation)
} }


/** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a /** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a
Expand Down Expand Up @@ -162,7 +163,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
templatesCache += (sym -> this) templatesCache += (sym -> this)
lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name)
override def toRoot: List[DocTemplateImpl] = this :: inTpl.toRoot override def toRoot: List[DocTemplateImpl] = this :: inTpl.toRoot
def inSource = if (sym.sourceFile != null) Some(sym.sourceFile, sym.pos.line) else None def inSource = if (sym.sourceFile != null) Some((sym.sourceFile, sym.pos.line)) else None
def sourceUrl = { def sourceUrl = {
def fixPath(s: String) = s.replaceAll("\\" + java.io.File.separator, "/") def fixPath(s: String) = s.replaceAll("\\" + java.io.File.separator, "/")
val assumedSourceRoot: String = { val assumedSourceRoot: String = {
Expand Down Expand Up @@ -375,6 +376,37 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
throw new Error("'" + bSym + "' that isn't a class, trait or object cannot be built as a documentable template") throw new Error("'" + bSym + "' that isn't a class, trait or object cannot be built as a documentable template")
} }


/** */
def makeAnnotation(annot: AnnotationInfo): Annotation = {
val aSym = annot.atp.typeSymbol
new EntityImpl(aSym, makeTemplate(aSym.owner)) with Annotation {
def annotationClass =
makeTemplate(annot.atp.typeSymbol)
def arguments =
annotationClass match {
case aClass: Class =>
aClass.valueParams match {
case Nil => Nil
case vp :: vps =>
(vp zip annot.args) map { case (param, arg) =>
new ValueArgument {
def parameter = Some(param)
def value = makeTree(arg)
}
}
}
case _ =>
annot.args map { arg =>
new ValueArgument {
def parameter = None
def value = makeTree(arg)
}
}
}

}
}

/** */ /** */
def makeMember(aSym: Symbol, inTpl: => DocTemplateImpl): List[MemberImpl] = { def makeMember(aSym: Symbol, inTpl: => DocTemplateImpl): List[MemberImpl] = {


Expand Down Expand Up @@ -457,17 +489,17 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def isTypeParam = false def isTypeParam = false
def isValueParam = true def isValueParam = true
def defaultValue = def defaultValue =
if (aSym.hasDefault) if (aSym.hasDefault) {
// units.filter should return only one element // units.filter should return only one element
(currentRun.units filter (_.source.file == aSym.sourceFile)).toList match { (currentRun.units filter (_.source.file == aSym.sourceFile)).toList match {
case List(unit) => case List(unit) =>
(unit.body find (_.symbol == aSym)) match { (unit.body find (_.symbol == aSym)) match {
case Some(ValDef(_,_,_,rhs)) => case Some(ValDef(_,_,_,rhs)) => Some(makeTree(rhs))
Some(makeTree(rhs))
case _ => None case _ => None
} }
case _ => None case _ => None
} }
}
else None else None
def resultType = def resultType =
makeType(sym.tpe, inTpl, sym) makeType(sym.tpe, inTpl, sym)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/doc/model/TreeEntity.scala
Expand Up @@ -13,4 +13,4 @@ import scala.collection.immutable.TreeMap
class TreeEntity { class TreeEntity {
var expression:String = "" var expression:String = ""
var refs = new TreeMap[Int, (Entity, Int)] // start, (Entity to be linked to , end) var refs = new TreeMap[Int, (Entity, Int)] // start, (Entity to be linked to , end)
} }

0 comments on commit 4659d81

Please sign in to comment.