From 184cac8ebc23aaa912d760649f80484d3adbb2b2 Mon Sep 17 00:00:00 2001 From: Eugene Vigdorchik Date: Mon, 15 Apr 2013 13:07:04 +0400 Subject: SI-7367 scaladoc crash on constructing the model for annotations. Scaladoc only checks primary constructor when building annotation model. Here we instead find the constructor matching the annotation's symbol. Also change TreeFactory.makeTree to return TreeEntity rather than Option[TreeEntity] and force the caller check for EmptyTree. --- .../scala/tools/nsc/doc/model/ModelFactory.scala | 43 ++++++++++++---------- .../scala/tools/nsc/doc/model/TreeFactory.scala | 13 +++---- test/scaladoc/run/SI-7367.check | 1 + test/scaladoc/run/SI-7367.scala | 25 +++++++++++++ 4 files changed, 55 insertions(+), 27 deletions(-) create mode 100755 test/scaladoc/run/SI-7367.check create mode 100755 test/scaladoc/run/SI-7367.scala diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 0a469c9227..d9b173bc43 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -897,32 +897,36 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } } - /** */ def makeAnnotation(annot: AnnotationInfo): scala.tools.nsc.doc.model.Annotation = { val aSym = annot.symbol new EntityImpl(aSym, makeTemplate(aSym.owner)) with scala.tools.nsc.doc.model.Annotation { lazy val annotationClass = makeTemplate(annot.symbol) - val arguments = { // lazy - def noParams = annot.args map { _ => None } - val params: List[Option[ValueParam]] = annotationClass match { + val arguments = { + val paramsOpt: Option[List[ValueParam]] = annotationClass match { case aClass: DocTemplateEntity with Class => - (aClass.primaryConstructor map { _.valueParams.head }) match { - case Some(vps) => vps map { Some(_) } - case None => noParams + val constr = aClass.constructors collectFirst { + case c: MemberImpl if c.sym == annot.original.symbol => c } - case _ => noParams + constr flatMap (_.valueParams.headOption) + case _ => None } - assert(params.length == annot.args.length) - (params zip annot.args) flatMap { case (param, arg) => - makeTree(arg) match { - case Some(tree) => - Some(new ValueArgument { - def parameter = param + val argTrees = annot.args map makeTree + paramsOpt match { + case Some (params) => + params zip argTrees map { case (param, tree) => + new ValueArgument { + def parameter = Some(param) def value = tree - }) - case None => None - } + } + } + case None => + argTrees map { tree => + new ValueArgument { + def parameter = None + def value = tree + } + } } } } @@ -962,9 +966,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { sym.name == aSym.name && sym.isParamWithDefault ) - (unit.body find (t => isCorrespondingParam(t.symbol))) match { - case Some(ValDef(_,_,_,rhs)) => makeTree(rhs) - case _ => None + unit.body find (t => isCorrespondingParam(t.symbol)) collect { + case ValDef(_,_,_,rhs) if rhs ne EmptyTree => makeTree(rhs) } case _ => None } diff --git a/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala b/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala index bd7534ded4..fdad84d0bc 100755 --- a/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/TreeFactory.scala @@ -19,7 +19,7 @@ trait TreeFactory { thisTreeFactory: ModelFactory with TreeFactory => val global: Global import global._ - def makeTree(rhs: Tree): Option[TreeEntity] = { + def makeTree(rhs: Tree): TreeEntity = { var expr = new StringBuilder var refs = new immutable.TreeMap[Int, (Entity, Int)] // start, (Entity to be linked to , end) @@ -80,17 +80,16 @@ trait TreeFactory { thisTreeFactory: ModelFactory with TreeFactory => traverser.traverse(rhs) - Some(new TreeEntity { + new TreeEntity { val expression = expr.toString val refEntity = refs - }) + } } - case pos: OffsetPosition => - Some(new TreeEntity { + case _ => + new TreeEntity { val expression = rhs.toString val refEntity = new immutable.TreeMap[Int, (Entity, Int)] - }) - case _ => None + } } } } diff --git a/test/scaladoc/run/SI-7367.check b/test/scaladoc/run/SI-7367.check new file mode 100755 index 0000000000..3925a0d464 --- /dev/null +++ b/test/scaladoc/run/SI-7367.check @@ -0,0 +1 @@ +Done. \ No newline at end of file diff --git a/test/scaladoc/run/SI-7367.scala b/test/scaladoc/run/SI-7367.scala new file mode 100755 index 0000000000..6e5a317932 --- /dev/null +++ b/test/scaladoc/run/SI-7367.scala @@ -0,0 +1,25 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + override def code = """ + class annot() extends annotation.StaticAnnotation { + def this(a: Any) = this() + } + + @annot(0) + class B + """ + + def scaladocSettings = "" + + def testModel(root: Package) = { + import access._ + val annotations = root._class("B").annotations + assert(annotations.size == 1) + assert(annotations(0).annotationClass == root._class("annot")) + val args = annotations(0).arguments + assert(args.size == 1) + assert(args(0).value.expression == "0") + } +} -- cgit v1.2.3