diff options
Diffstat (limited to 'src/compiler')
19 files changed, 195 insertions, 117 deletions
diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala index 61db3c7fa9..03cb770474 100644 --- a/src/compiler/scala/tools/ant/Scaladoc.scala +++ b/src/compiler/scala/tools/ant/Scaladoc.scala @@ -671,7 +671,7 @@ class Scaladoc extends ScalaMatchingTask { exception.printStackTrace() safeBuildError("Document failed because of an internal documenter error (" + exception.getMessage + "); see the error output for details.") - case exception => + case exception : Throwable => exception.printStackTrace() safeBuildError("Document failed because of an internal documenter error " + "(no error message provided); see the error output for details.") diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala index 7cb539feee..7662381186 100644 --- a/src/compiler/scala/tools/nsc/doc/Settings.scala +++ b/src/compiler/scala/tools/nsc/doc/Settings.scala @@ -183,6 +183,11 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) "" ) + val docExpandAllTypes = BooleanSetting ( + "-expand-all-types", + "Expand all type aliases and abstract types into full template pages. (locally this can be done with the @template annotation)" + ) + // Somewhere slightly before r18708 scaladoc stopped building unless the // self-type check was suppressed. I hijacked the slotted-for-removal-anyway // suppress-vt-warnings option and renamed it for this purpose. @@ -195,7 +200,8 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) docDiagramsDotTimeout, docDiagramsDotRestart, docImplicits, docImplicitsDebug, docImplicitsShowAll, docDiagramsMaxNormalClasses, docDiagramsMaxImplicitClasses, - docNoPrefixes, docNoLinkWarnings, docRawOutput, docSkipPackages + docNoPrefixes, docNoLinkWarnings, docRawOutput, docSkipPackages, + docExpandAllTypes ) val isScaladocSpecific: String => Boolean = scaladocSpecific map (_.name) diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala index 18cc65092b..436425df83 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -53,11 +53,16 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { "trait.png", "trait_big.png", "trait_diagram.png", + "type.png", + "type_big.png", + "type_diagram.png", "class_to_object_big.png", "object_to_class_big.png", - "object_to_trait_big.png", "trait_to_object_big.png", + "object_to_trait_big.png", + "type_to_object_big.png", + "object_to_type_big.png", "arrow-down.png", "arrow-right.png", diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index 226ed49aca..aa2df57967 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -211,10 +211,12 @@ abstract class HtmlPage extends Page { thisPage => else if (ety.isTrait) "trait_big.png" else if (ety.isClass && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "class_to_object_big.png" else if (ety.isClass) "class_big.png" + else if ((ety.isAbstractType || ety.isAliasType) && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "type_to_object_big.png" + else if ((ety.isAbstractType || ety.isAliasType)) "type_big.png" else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && ety.companion.get.isClass) "object_to_class_big.png" else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && ety.companion.get.isTrait) "object_to_trait_big.png" + else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && (ety.companion.get.isAbstractType || ety.companion.get.isAliasType)) "object_to_trait_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/ReferenceIndex.scala b/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala index a76cc231b4..effaee711d 100755 --- a/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala @@ -34,7 +34,7 @@ class ReferenceIndex(letter: Char, index: doc.Index, universe: Universe) extends } else { html } - }) + }).toList.distinct <div class="entry"> <div class="name">{ 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 d691692920..487ef447e9 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -92,7 +92,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <p id="owner">{ templatesToHtml(tpl.inTemplate.toRoot.reverse.tail, xml.Text(".")) }</p> } - <body class={ if (tpl.isTrait || tpl.isClass || tpl.qualifiedName == "scala.AnyRef") "type" else "value" }> + <body class={ if (tpl.isType) "type" else "value" }> <div id="definition"> { tpl.companion match { @@ -734,20 +734,21 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } }{ if (isReduced) NodeSeq.Empty else { mbr match { - case tpl: DocTemplateEntity if !tpl.parentTypes.isEmpty => - <span class="result"> extends { typeToHtml(tpl.parentTypes.map(_._2), hasLinks) }</span> - case tme: MemberEntity if (tme.isDef || tme.isVal || tme.isLazyVal || tme.isVar) => <span class="result">: { typeToHtml(tme.resultType, hasLinks) }</span> - case abt: AbstractType => + case abt: MemberEntity with AbstractType => val b2s = boundsToHtml(abt.hi, abt.lo, hasLinks) if (b2s != NodeSeq.Empty) <span class="result">{ b2s }</span> else NodeSeq.Empty - case alt: AliasType => + case alt: MemberEntity with AliasType => <span class="result"> = { typeToHtml(alt.alias, hasLinks) }</span> + + case tpl: MemberTemplateEntity if !tpl.parentTypes.isEmpty => + <span class="result"> extends { typeToHtml(tpl.parentTypes.map(_._2), hasLinks) }</span> + case _ => NodeSeq.Empty } }} diff --git a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala index f3454f71b8..bae61f1a3b 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala @@ -242,6 +242,8 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { attr ++= classStyle else if(node.isObjectNode) attr ++= objectStyle + else if(node.isTypeNode) + attr ++= typeStyle else attr ++= defaultStyle @@ -254,6 +256,8 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { img = "class_diagram.png" else if(node.isObjectNode) img = "object_diagram.png" + else if(node.isTypeNode) + img = "type_diagram.png" if(!img.equals("")) { img = "<TD><IMG SCALE=\"TRUE\" SRC=\"" + settings.outdir.value + "/lib/" + img + "\" /></TD>" @@ -307,6 +311,8 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { space + "trait" else if (node.isObjectNode) space + "object" + else if (node.isTypeNode) + space + "type" else default @@ -491,6 +497,12 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { "fontcolor" -> "#ffffff" ) + private val typeStyle = Map( + "color" -> "#115F3B", + "fillcolor" -> "#0A955B", + "fontcolor" -> "#ffffff" + ) + private def flatten(attributes: Map[String, String]) = attributes.map{ case (key, value) => key + "=\"" + value + "\"" }.mkString(", ") private val graphAttributesStr = graphAttributes.map{ case (key, value) => key + "=\"" + value + "\";\n" }.mkString diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css index 04d29580b7..5fe33f72f5 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css @@ -119,6 +119,14 @@ svg.class-diagram .node.this.trait.over polygon fill: #235d7b; } +svg.package-diagram .node.type.over polygon, +svg.class-diagram .node.this.type.over polygon +{ + fill: #098552; + fill: #04663e; +} + + svg.package-diagram .node.object.over polygon { fill: #183377; diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js index eb7f752440..f29438edfb 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js @@ -15,15 +15,15 @@ var lastHash = ""; $(document).ready(function() { $('body').layout({ west__size: '20%' }); - $('#browser').layout({ + $('#browser').layout({ center__paneSelector: ".ui-west-center" //,center__initClosed:true ,north__paneSelector: ".ui-west-north" - }); + }); $('iframe').bind("load", function(){ var subtitle = $(this).contents().find('title').text(); $(document).attr('title', (title ? title + " - " : "") + subtitle); - + setUrlFragmentFromFrameSrc(); }); @@ -81,16 +81,16 @@ function setUrlFragmentFromFrameSrc() { var commonLength = location.pathname.lastIndexOf("/"); var frameLocation = frames["template"].location; var relativePath = frameLocation.pathname.slice(commonLength + 1); - + if(!relativePath || frameLocation.pathname.indexOf("/") < 0) return; - + // Add #, remove ".html" and replace "/" with "." fragment = "#" + relativePath.replace(/\.html$/, "").replace(/\//g, "."); - + // Add the frame's hash after an @ if(frameLocation.hash) fragment += ("@" + frameLocation.hash.slice(1)); - + // Use replace to not add history items lastFragment = fragment; location.replace(fragment); @@ -109,7 +109,7 @@ var Index = {}; if (type == 'object') { href = t['object']; } else { - href = t['class'] || t['trait'] || t['case class']; + href = t['class'] || t['trait'] || t['case class'] || t['type']; } return [ '<a class="tplshow" target="template" href="', @@ -142,10 +142,10 @@ var Index = {}; inner += openLink(template, 'object'); } - if (template['class'] || template['trait'] || template['case class']) { + if (template['class'] || template['trait'] || template['case class'] || template['type']) { inner += (inner == '') ? '<div class="placeholder" />' : '</a>'; - inner += openLink(template, template['trait'] ? 'trait' : 'class'); + inner += openLink(template, template['trait'] ? 'trait' : template['type'] ? 'type' : 'class'); } else { inner += '<div class="placeholder"/>'; } @@ -245,6 +245,7 @@ function configureEntityList() { function prepareEntityList() { var classIcon = $("#library > img.class"); var traitIcon = $("#library > img.trait"); + var typeIcon = $("#library > img.type"); var objectIcon = $("#library > img.object"); var packageIcon = $("#library > img.package"); @@ -252,6 +253,7 @@ function prepareEntityList() { $('#tpl li.pack').each(function () { $("span.class", this).each(function() { $(this).replaceWith(classIcon.clone()); }); $("span.trait", this).each(function() { $(this).replaceWith(traitIcon.clone()); }); + $("span.type", this).each(function() { $(this).replaceWith(typeIcon.clone()); }); $("span.object", this).each(function() { $(this).replaceWith(objectIcon.clone()); }); $("span.package", this).each(function() { $(this).replaceWith(packageIcon.clone()); }); }); @@ -265,11 +267,11 @@ function keyboardScrolldownLeftPane() { scheduler.add("init", function() { $("#textfilter input").blur(); var $items = $("#tpl li"); - $items.first().addClass('selected'); + $items.first().addClass('selected'); $(window).bind("keydown", function(e) { var $old = $items.filter('.selected'), - $new; + $new; switch ( e.keyCode ) { @@ -286,7 +288,7 @@ function keyboardScrolldownLeftPane() { case 27: // escape $old.removeClass('selected'); $(window).unbind(e); - $("#textfilter input").focus(); + $("#textfilter input").focus(); break; @@ -296,7 +298,7 @@ function keyboardScrolldownLeftPane() { if (!$new.length) { $new = $old.parent().prev(); } - + if ($new.is('ol') && $new.children(':last').is('ol')) { $new = $new.children().children(':last'); } else if ($new.is('ol')) { @@ -313,17 +315,17 @@ function keyboardScrolldownLeftPane() { if ($new.is('ol')) { $new = $new.children(':first'); } - break; - } - + break; + } + if ($new.is('li')) { $old.removeClass('selected'); - $new.addClass('selected'); + $new.addClass('selected'); } else if (e.keyCode == 38) { $(window).unbind(e); $("#textfilter input").focus(); } - }); + }); }); } @@ -342,13 +344,13 @@ function configureTextFilter() { $("#template").contents().find("#mbrsel-input").focus(); input.attr("value", ""); return false; - } + } if (event.keyCode == 40) { // down arrow $(window).unbind("keydown"); keyboardScrolldownLeftPane(); return false; - } - textFilter(); + } + textFilter(); }); input.focus(function(event) { input.select(); }); }); @@ -419,7 +421,7 @@ function textFilter() { }); configureHideFilter(); }; - + scheduler.add('filter', searchLoop); } diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png Binary files differnew file mode 100644 index 0000000000..7502942eb6 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png Binary files differnew file mode 100644 index 0000000000..366ec4e992 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png Binary files differnew file mode 100644 index 0000000000..df0dc118bf --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png Binary files differnew file mode 100644 index 0000000000..d6fbb84ff2 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png Binary files differnew file mode 100644 index 0000000000..1bd2833a63 --- /dev/null +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala index 620aa4253f..0836d7e4da 100644 --- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala +++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala @@ -241,6 +241,11 @@ trait MemberTemplateEntity extends TemplateEntity with MemberEntity with HigherK /** The value parameters of this case class, or an empty list if this class is not a case class. As case class value * parameters cannot be curried, the outer list has exactly one element. */ def valueParams: List[List[ValueParam]] + + /** The direct super-type of this template + e.g: {{{class A extends B[C[Int]] with D[E]}}} will have two direct parents: class B and D + NOTE: we are dropping the refinement here! */ + def parentTypes: List[(TemplateEntity, TypeEntity)] } /** A template (class, trait, object or package) for which documentation is available. Only templates for which @@ -259,11 +264,6 @@ trait DocTemplateEntity extends MemberTemplateEntity { * only if the `docsourceurl` setting has been set. */ def sourceUrl: Option[java.net.URL] - /** The direct super-type of this template - e.g: {{{class A extends B[C[Int]] with D[E]}}} will have two direct parents: class B and D - NOTE: we are dropping the refinement here! */ - def parentTypes: List[(TemplateEntity, TypeEntity)] - /** All class, trait and object templates which are part of this template's linearization, in lineratization order. * This template's linearization contains all of its direct and indirect super-classes and super-traits. */ def linearizationTemplates: List[TemplateEntity] diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index fc5fde3239..0ba32fceaa 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -265,6 +265,32 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { override def isNoDocMemberTemplate = true lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name) def valueParams: List[List[ValueParam]] = Nil /** TODO, these are now only computed for DocTemplates */ + + // Seems unused + // def parentTemplates = + // if (sym.isPackage || sym == AnyClass) + // List() + // else + // sym.tpe.parents.flatMap { tpe: Type => + // val tSym = tpe.typeSymbol + // if (tSym != NoSymbol) + // List(makeTemplate(tSym)) + // else + // List() + // } filter (_.isInstanceOf[DocTemplateEntity]) + + def parentTypes = + if (sym.isPackage || sym == AnyClass) List() else { + val tps = (this match { + case a: AliasType => sym.tpe.dealias.parents + case a: AbstractType => sym.info.bounds match { + case TypeBounds(lo, hi) => List(hi) + case _ => Nil + } + case _ => sym.tpe.parents + }) map { _.asSeenFrom(sym.thisType, sym) } + makeParentTypes(RefinedType(tps, EmptyScope), Some(this), inTpl) + } } /** The instantiation of `TemplateImpl` triggers the creation of the following entities: @@ -306,24 +332,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { else None } - def parentTemplates = - if (sym.isPackage || sym == AnyClass) - List() - else - sym.tpe.parents.flatMap { tpe: Type => - val tSym = tpe.typeSymbol - if (tSym != NoSymbol) - List(makeTemplate(tSym)) - else - List() - } filter (_.isInstanceOf[DocTemplateEntity]) - - def parentTypes = - if (sym.isPackage || sym == AnyClass) List() else { - val tps = sym.tpe.parents map { _.asSeenFrom(sym.thisType, sym) } - makeParentTypes(RefinedType(tps, EmptyScope), Some(this), inTpl) - } - protected def linearizationFromSymbol(symbol: Symbol): List[(TemplateEntity, TypeEntity)] = { symbol.ancestors map { ancestor => val typeEntity = makeType(symbol.info.baseType(ancestor), this) @@ -378,7 +386,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // the direct members (methods, values, vars, types and directly contained templates) var memberSymsEager = memberSyms.filter(!memberSymsLazy.contains(_)) // the members generated by the symbols in memberSymsEager - val ownMembers = (memberSyms.flatMap(makeMember(_, None, this))) + val ownMembers = (memberSymsEager.flatMap(makeMember(_, None, this))) // all the members that are documentented PLUS the members inherited by implicit conversions var members: List[MemberImpl] = ownMembers @@ -395,11 +403,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { */ def completeModel: Unit = { // DFS completion - for (member <- members) - member match { - case d: DocTemplateImpl => d.completeModel - case _ => - } + // since alias types and abstract types have no own members, there's no reason for them to call completeModel + if (!sym.isAliasType && !sym.isAbstractType) + for (member <- members) + member match { + case d: DocTemplateImpl => d.completeModel + case _ => + } members :::= memberSymsLazy.map(modelCreation.createLazyTemplateMember(_, this)) @@ -432,15 +442,33 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { override def isTemplate = true override def isDocTemplate = true - def companion = sym.companionSymbol match { - case NoSymbol => None - case comSym if !isEmptyJavaObject(comSym) && (comSym.isClass || comSym.isModule) => - makeTemplate(comSym) match { - case d: DocTemplateImpl => Some(d) - case _ => None + private[this] lazy val companionSymbol = + if (sym.isAliasType || sym.isAbstractType) { + inTpl.sym.info.member(sym.name.toTermName) match { + case NoSymbol => NoSymbol + case s => + s.info match { + case ot: OverloadedType => + NoSymbol + case _ => + // that's to navigate from val Foo: FooExtractor to FooExtractor :) + s.info.resultType.typeSymbol + } } - case _ => None - } + } + else + sym.companionSymbol + + def companion = + companionSymbol match { + case NoSymbol => None + case comSym if !isEmptyJavaObject(comSym) && (comSym.isClass || comSym.isModule) => + makeTemplate(comSym) match { + case d: DocTemplateImpl => Some(d) + case _ => None + } + case _ => None + } def constructors: List[MemberImpl with Constructor] = if (isClass) members collect { case d: Constructor => d } else Nil def primaryConstructor: Option[MemberImpl with Constructor] = if (isClass) constructors find { _.isPrimary } else None @@ -523,6 +551,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { val name = optimize(sym.nameString) } + private trait AliasImpl { + def sym: Symbol + def inTpl: TemplateImpl + def alias = makeTypeInTemplateContext(sym.tpe.dealias, inTpl, sym) + } + private trait TypeBoundsImpl { def sym: Symbol def inTpl: TemplateImpl @@ -591,13 +625,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def createRootPackage: PackageImpl = docTemplatesCache.get(RootPackage) match { case Some(root: PackageImpl) => root - case _ => modelCreation.createTemplate(RootPackage, null).asInstanceOf[PackageImpl] + case _ => modelCreation.createTemplate(RootPackage, null) match { + case Some(root: PackageImpl) => root + case _ => sys.error("Scaladoc: Unable to create root package!") + } } /** * Create a template, either a package, class, trait or object */ - def createTemplate(aSym: Symbol, inTpl: DocTemplateImpl): DocTemplateImpl = { + def createTemplate(aSym: Symbol, inTpl: DocTemplateImpl): Option[MemberImpl] = { // don't call this after the model finished! assert(!modelFinished) @@ -616,11 +653,15 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def createDocTemplate(bSym: Symbol, inTpl: DocTemplateImpl): DocTemplateImpl = { assert(!modelFinished) // only created BEFORE the model is finished - if (bSym.isModule || (bSym.isAliasType && bSym.tpe.typeSymbol.isModule)) + if (bSym.isAliasType && bSym != AnyRefClass) + new DocTemplateImpl(bSym, inTpl) with AliasImpl with AliasType { override def isAliasType = true } + else if (bSym.isAbstractType) + new DocTemplateImpl(bSym, inTpl) with TypeBoundsImpl with AbstractType { override def isAbstractType = true } + else if (bSym.isModule) new DocTemplateImpl(bSym, inTpl) with Object {} - else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait)) + else if (bSym.isTrait) new DocTemplateImpl(bSym, inTpl) with Trait {} - else if (bSym.isClass || (bSym.isAliasType && bSym.tpe.typeSymbol.isClass)) + else if (bSym.isClass || bSym == AnyRefClass) new DocTemplateImpl(bSym, inTpl) with Class {} else sys.error("'" + bSym + "' isn't a class, trait or object thus cannot be built as a documentable template.") @@ -628,7 +669,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { val bSym = normalizeTemplate(aSym) if (docTemplatesCache isDefinedAt bSym) - return docTemplatesCache(bSym) + return Some(docTemplatesCache(bSym)) /* Three cases of templates: * (1) root package -- special cased for bootstrapping @@ -636,7 +677,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { * (3) class/object/trait */ if (bSym == RootPackage) // (1) - new RootPackageImpl(bSym) { + Some(new RootPackageImpl(bSym) { override lazy val comment = createRootPackageComment override val name = "root" override def inTemplate = this @@ -648,21 +689,28 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { (bSym.info.members ++ EmptyPackage.info.members) filter { s => s != EmptyPackage && s != RootPackage } - } + }) else if (bSym.isPackage) // (2) - inTpl match { - case inPkg: PackageImpl => - val pack = new PackageImpl(bSym, inPkg) {} - if (pack.templates.filter(_.isDocTemplate).isEmpty && pack.memberSymsLazy.isEmpty) - droppedPackages += pack - pack - case _ => - sys.error("'" + bSym + "' must be in a package") - } + if (settings.skipPackage(makeQualifiedName(bSym))) + None + else + inTpl match { + case inPkg: PackageImpl => + val pack = new PackageImpl(bSym, inPkg) {} + // Used to check package pruning works: + //println(pack.qualifiedName) + if (pack.templates.filter(_.isDocTemplate).isEmpty && pack.memberSymsLazy.isEmpty) { + droppedPackages += pack + None + } else + Some(pack) + case _ => + sys.error("'" + bSym + "' must be in a package") + } else { // no class inheritance at this point - assert(inOriginalOwner(bSym, inTpl)) - createDocTemplate(bSym, inTpl) + assert(inOriginalOwner(bSym, inTpl) || bSym.isAbstractType || bSym.isAliasType, bSym + " in " + inTpl) + Some(createDocTemplate(bSym, inTpl)) } } @@ -750,28 +798,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { Some(new NonTemplateMemberImpl(bSym, conversion, useCaseOf, inTpl) with Val { override def isVal = true }) - else if (bSym.isAbstractType) + else if (bSym.isAbstractType && !typeShouldDocument(bSym, inTpl)) Some(new MemberTemplateImpl(bSym, inTpl) with TypeBoundsImpl with AbstractType { override def isAbstractType = true }) - else if (bSym.isAliasType && bSym != AnyRefClass) - Some(new MemberTemplateImpl(bSym, inTpl) with AliasType { + else if (bSym.isAliasType && !typeShouldDocument(bSym, inTpl)) + Some(new MemberTemplateImpl(bSym, inTpl) with AliasImpl with AliasType { override def isAliasType = true - def alias = makeTypeInTemplateContext(sym.tpe.dealias, inTpl, sym) }) - else if (bSym.isPackage && !modelFinished) - if (settings.skipPackage(makeQualifiedName(bSym))) None else - inTpl match { - case inPkg: PackageImpl => modelCreation.createTemplate(bSym, inTpl) match { - case p: PackageImpl if droppedPackages contains p => None - case p: PackageImpl => Some(p) - case _ => sys.error("'" + bSym + "' must be a package") - } - case _ => - sys.error("'" + bSym + "' must be in a package") - } - else if (!modelFinished && templateShouldDocument(bSym, inTpl) && inOriginalOwner(bSym, inTpl)) - Some(modelCreation.createTemplate(bSym, inTpl)) + else if (!modelFinished && (bSym.isPackage || bSym.isAliasType || bSym.isAbstractType || templateShouldDocument(bSym, inTpl))) + modelCreation.createTemplate(bSym, inTpl) else None } @@ -915,7 +951,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } /** Get the types of the parents of the current class, ignoring the refinements */ - def makeParentTypes(aType: Type, tpl: Option[DocTemplateImpl], inTpl: TemplateImpl): List[(TemplateEntity, TypeEntity)] = aType match { + def makeParentTypes(aType: Type, tpl: Option[MemberTemplateImpl], inTpl: TemplateImpl): List[(TemplateEntity, TypeEntity)] = aType match { case RefinedType(parents, defs) => val ignoreParents = Set[Symbol](AnyClass, AnyRefClass, ObjectClass) val filtParents = @@ -978,7 +1014,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { normalizeTemplate(aSym.owner) == normalizeTemplate(inTpl.sym) def templateShouldDocument(aSym: Symbol, inTpl: TemplateImpl): Boolean = - (aSym.isClass || aSym.isModule || aSym == AnyRefClass) && + (aSym.isTrait || aSym.isClass || aSym.isModule) && localShouldDocument(aSym) && !isEmptyJavaObject(aSym) && // either it's inside the original owner or we can document it later: @@ -1014,5 +1050,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // the implicit conversions that are excluded from the pages should not appear in the diagram def implicitExcluded(convertorMethod: String): Boolean = settings.hardcoded.commonConversionTargets.contains(convertorMethod) + + // whether or not to create a page for an {abstract,alias} type + def typeShouldDocument(bSym: Symbol, inTpl: DocTemplateImpl) = + (settings.docExpandAllTypes.value && (bSym.sourceFile != null)) || + global.expandedDocComment(bSym, inTpl.sym).contains("@template") } 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 df913555a7..a57ccd36c2 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -350,7 +350,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory with Member case None => List.empty } - val tagsWithoutDiagram = tags.filterNot(pair => pair._1 == inheritDiagramTag || pair._1 == contentDiagramTag) + val stripTags=List(inheritDiagramTag, contentDiagramTag, SimpleTagKey("template")) + val tagsWithoutDiagram = tags.filterNot(pair => stripTags.contains(pair._1)) val bodyTags: mutable.Map[TagKey, List[Body]] = mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWiki(_, pos, inTplOpt))} toSeq: _*) diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala index 902d5da240..c2aa1f17f3 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala @@ -70,7 +70,8 @@ abstract class Node { def isClassNode = if (tpl.isDefined) (tpl.get.isClass || tpl.get.qualifiedName == "scala.AnyRef") else false def isTraitNode = if (tpl.isDefined) tpl.get.isTrait else false def isObjectNode= if (tpl.isDefined) tpl.get.isObject else false - def isOtherNode = !(isClassNode || isTraitNode || isObjectNode) + def isTypeNode = if (doctpl.isDefined) doctpl.get.isAbstractType || doctpl.get.isAliasType else false + def isOtherNode = !(isClassNode || isTraitNode || isObjectNode || isTypeNode) def isImplicitNode = false def isOutsideNode = false def tooltip: Option[String] @@ -91,6 +92,7 @@ abstract class Node { object Node { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = Some((n.tpe, n.tpl)) } object ClassNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isClassNode) Some((n.tpe, n.tpl)) else None } object TraitNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isTraitNode) Some((n.tpe, n.tpl)) else None } +object TypeNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isTypeNode) Some((n.tpe, n.tpl)) else None } object ObjectNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isObjectNode) Some((n.tpe, n.tpl)) else None } object OutsideNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isOutsideNode) Some((n.tpe, n.tpl)) else None } object OtherNode { def unapply(n: Node): Option[(TypeEntity, Option[TemplateEntity])] = if (n.isOtherNode) Some((n.tpe, n.tpl)) else None } diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala index e0f6d42a68..2645d8fd14 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala @@ -121,12 +121,10 @@ trait DiagramFactory extends DiagramDirectiveParser { // for each node, add its subclasses for (node <- nodesAll if !classExcluded(node)) { node match { - case dnode: DocTemplateImpl => - var superClasses = dnode.parentTypes.map(_._1) + case dnode: MemberTemplateImpl => + var superClasses = dnode.parentTypes.map(_._1).filter(nodesAll.contains(_)) - superClasses = superClasses.filter(nodesAll.contains(_)) - - // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to change the diagrams. + // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to add nodes to diagrams. if (pack.sym == ScalaPackage) if (dnode.sym == NullClass) superClasses = List(makeTemplate(AnyRefClass)) @@ -142,7 +140,7 @@ trait DiagramFactory extends DiagramDirectiveParser { } mapNodes += node -> ( - if (node.inTemplate == pack && !node.isNoDocMemberTemplate) + if (node.inTemplate == pack && (node.isDocTemplate || node.isAbstractType || node.isAliasType)) NormalNode(node.resultType, Some(node))() else OutsideNode(node.resultType, Some(node))() |