summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Ureche <vlad.ureche@gmail.com>2012-07-16 23:12:35 +0200
committerVlad Ureche <vlad.ureche@gmail.com>2012-07-17 14:20:13 +0200
commitdac4e8f543a8e2e3bacf447d327fc8a7e99acb49 (patch)
tree31c720a63ef9edd1608b7ed6511d2a6dfa77964d
parent17f745d33cbda90aa552c95bc5456ed793180333 (diff)
downloadscala-dac4e8f543a8e2e3bacf447d327fc8a7e99acb49.tar.gz
scala-dac4e8f543a8e2e3bacf447d327fc8a7e99acb49.tar.bz2
scala-dac4e8f543a8e2e3bacf447d327fc8a7e99acb49.zip
SI-5784 Scaladoc: {Abstract,Alias} type templates
Normally scaladoc won't generate template pages for anything other than packages, classes, traits and objects. But using the @template annotation on {abstract,alias} types, they get their own page and take part as full members in the diagrams. Furthermore, when looking for the companion object, if a value of type T is in scope, T will be taken as the companion object (even though it might be a class) All templates, including types are listed on the left navigation pane, so now adding @template to String can get scaladoc to generate (a no-comments) page for java.lang.String. The {abstract, alias} type icons need to be updated -- I just took the class icons and added a small x to them -- but they shoud be something else (maybe an underscore?)i TO USE THIS PATCH: <pre> /** @contentDiagram */ // tells scaladoc to create a diagram of the // templates contained in trait Base trait Base { /** @template */ // tells scaladoc to create a page for Foo type T < Foo trait Foo { def foo: Int } } /** @contentDiagram */ trait Api extends Base { /** @template */ override type T <: FooApi trait FooApi extends Foo { def bar: String } } </pre>
-rw-r--r--src/compiler/scala/tools/ant/Scaladoc.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/Settings.scala8
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala7
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala4
-rwxr-xr-xsrc/compiler/scala/tools/nsc/doc/html/page/ReferenceIndex.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala13
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala12
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/diagrams.css8
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js48
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.pngbin0 -> 9158 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type.pngbin0 -> 3338 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.pngbin0 -> 7691 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.pngbin0 -> 3895 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.pngbin0 -> 9054 bytes
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/Entity.scala10
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala181
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala3
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala10
-rw-r--r--src/library-aux/scala/AnyRef.scala1
-rw-r--r--src/partest/scala/tools/partest/ScaladocModelTest.scala10
-rw-r--r--test/scaladoc/resources/SI-5784.scala28
-rw-r--r--test/scaladoc/resources/doc-root/AnyRef.scala1
-rw-r--r--test/scaladoc/run/SI-5533.scala4
-rw-r--r--test/scaladoc/run/SI-5784.check1
-rw-r--r--test/scaladoc/run/SI-5784.scala44
26 files changed, 281 insertions, 120 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
new file mode 100644
index 0000000000..7502942eb6
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/object_to_type_big.png
Binary files differ
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
new file mode 100644
index 0000000000..366ec4e992
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type.png
Binary files differ
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
new file mode 100644
index 0000000000..df0dc118bf
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_big.png
Binary files differ
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
new file mode 100644
index 0000000000..d6fbb84ff2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_diagram.png
Binary files differ
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
new file mode 100644
index 0000000000..1bd2833a63
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/type_to_object_big.png
Binary files differ
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))()
diff --git a/src/library-aux/scala/AnyRef.scala b/src/library-aux/scala/AnyRef.scala
index 1eefb0c806..7d8b9f9e76 100644
--- a/src/library-aux/scala/AnyRef.scala
+++ b/src/library-aux/scala/AnyRef.scala
@@ -10,6 +10,7 @@ package scala
/** Class `AnyRef` is the root class of all ''reference types''.
* All types except the value types descend from this class.
+ * @template
*/
trait AnyRef extends Any {
diff --git a/src/partest/scala/tools/partest/ScaladocModelTest.scala b/src/partest/scala/tools/partest/ScaladocModelTest.scala
index d8d5dfbbeb..adf7abe11c 100644
--- a/src/partest/scala/tools/partest/ScaladocModelTest.scala
+++ b/src/partest/scala/tools/partest/ScaladocModelTest.scala
@@ -130,11 +130,17 @@ abstract class ScaladocModelTest extends DirectTest {
def _conversion(name: String): ImplicitConversion = getTheFirst(_conversions(name), tpl.qualifiedName + ".conversion(" + name + ")")
def _conversions(name: String): List[ImplicitConversion] = tpl.conversions.filter(_.conversionQualifiedName == name)
- def _absType(name: String): MemberEntity = getTheFirst(_methods(name), tpl.qualifiedName + ".abstractType(" + name + ")")
+ def _absType(name: String): MemberEntity = getTheFirst(_absTypes(name), tpl.qualifiedName + ".abstractType(" + name + ")")
def _absTypes(name: String): List[MemberEntity] = tpl.members.filter(mbr => mbr.name == name && mbr.isAbstractType)
- def _aliasType(name: String): MemberEntity = getTheFirst(_methods(name), tpl.qualifiedName + ".aliasType(" + name + ")")
+ def _absTypeTpl(name: String): DocTemplateEntity = getTheFirst(_absTypeTpls(name), tpl.qualifiedName + ".abstractType(" + name + ")")
+ def _absTypeTpls(name: String): List[DocTemplateEntity] = tpl.members.collect({ case dtpl: DocTemplateEntity with AbstractType if dtpl.name == name => dtpl })
+
+ def _aliasType(name: String): MemberEntity = getTheFirst(_aliasTypes(name), tpl.qualifiedName + ".aliasType(" + name + ")")
def _aliasTypes(name: String): List[MemberEntity] = tpl.members.filter(mbr => mbr.name == name && mbr.isAliasType)
+
+ def _aliasTypeTpl(name: String): DocTemplateEntity = getTheFirst(_aliasTypeTpls(name), tpl.qualifiedName + ".aliasType(" + name + ")")
+ def _aliasTypeTpls(name: String): List[DocTemplateEntity] = tpl.members.collect({ case dtpl: DocTemplateEntity with AliasType if dtpl.name == name => dtpl })
}
class PackageAccess(pack: Package) extends TemplateAccess(pack) {
diff --git a/test/scaladoc/resources/SI-5784.scala b/test/scaladoc/resources/SI-5784.scala
new file mode 100644
index 0000000000..175cc3cf33
--- /dev/null
+++ b/test/scaladoc/resources/SI-5784.scala
@@ -0,0 +1,28 @@
+package test.templates {
+ object `package` {
+ /** @template */
+ type String = java.lang.String
+ val String = new StringCompanion
+ class StringCompanion { def boo = ??? }
+ }
+
+ /** @contentDiagram */
+ trait Base {
+ /** @template */
+ type String = test.templates.String
+ /** @template
+ * @inheritanceDiagram */
+ type T <: Foo
+ val T: FooExtractor
+ trait Foo { def foo: Int }
+ trait FooExtractor { def apply(foo: Int); def unapply(t: Foo): Option[Int] }
+ }
+
+ /** @contentDiagram */
+ trait Api extends Base {
+ /** @template
+ * @inheritanceDiagram */
+ override type T <: FooApi
+ trait FooApi extends Foo { def bar: String }
+ }
+}
diff --git a/test/scaladoc/resources/doc-root/AnyRef.scala b/test/scaladoc/resources/doc-root/AnyRef.scala
index 1eefb0c806..7d8b9f9e76 100644
--- a/test/scaladoc/resources/doc-root/AnyRef.scala
+++ b/test/scaladoc/resources/doc-root/AnyRef.scala
@@ -10,6 +10,7 @@ package scala
/** Class `AnyRef` is the root class of all ''reference types''.
* All types except the value types descend from this class.
+ * @template
*/
trait AnyRef extends Any {
diff --git a/test/scaladoc/run/SI-5533.scala b/test/scaladoc/run/SI-5533.scala
index e7b5f57860..989d9aa13a 100644
--- a/test/scaladoc/run/SI-5533.scala
+++ b/test/scaladoc/run/SI-5533.scala
@@ -32,6 +32,8 @@ object Test extends ScaladocModelTest {
val B = b._class("B")
val D = b._class("D")
testDiagram(B, B.contentDiagram, 2, 1)
- testDiagram(D, D.contentDiagram, 2, 1)
+ // unfortunately not all packages, as B1 extends A.this.A1 and it gets the wrong member -- maybe we should model
+ // things as we do for symbols?
+ testDiagram(D, D.contentDiagram, 3, 2)
}
} \ No newline at end of file
diff --git a/test/scaladoc/run/SI-5784.check b/test/scaladoc/run/SI-5784.check
new file mode 100644
index 0000000000..619c56180b
--- /dev/null
+++ b/test/scaladoc/run/SI-5784.check
@@ -0,0 +1 @@
+Done.
diff --git a/test/scaladoc/run/SI-5784.scala b/test/scaladoc/run/SI-5784.scala
new file mode 100644
index 0000000000..318eb78b2a
--- /dev/null
+++ b/test/scaladoc/run/SI-5784.scala
@@ -0,0 +1,44 @@
+import scala.tools.nsc.doc.model._
+import scala.tools.partest.ScaladocModelTest
+
+object Test extends ScaladocModelTest {
+
+ override def resourceFile: String = "SI-5784.scala"
+
+ // no need for special settings
+ def scaladocSettings = "-diagrams"
+
+ def testModel(rootPackage: Package) = {
+ // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s))
+ import access._
+
+ val main = rootPackage._package("test")._package("templates")
+
+ val String = main._aliasTypeTpl("String")
+ assert(String.companion.isDefined, "test.templates.String should have a pseudo-companion object")
+
+ val Base = main._trait("Base")
+ assert(Base.members.filter(_.inDefinitionTemplates.head == Base).length == 5, Base.members.filter(_.inDefinitionTemplates.head == Base).length + " == 5")
+ assert(Base.members.collect{case d: DocTemplateEntity => d}.length == 4, Base.members.collect{case d: DocTemplateEntity => d}.length == 4)
+ testDiagram(Base, Base.contentDiagram, 2, 1)
+
+ val BaseT = Base._absTypeTpl("T")
+ val Foo = Base._trait("Foo")
+ assert(BaseT.members.filter(_.inDefinitionTemplates.head == Base).length == 0, BaseT.members.filter(_.inDefinitionTemplates.head == Base).length + " == 0")
+ assert(BaseT.members.map(_.name).sorted == Foo.members.map(_.name).sorted, BaseT.members.map(_.name).sorted + " == " + Foo.members.map(_.name).sorted)
+ assert(BaseT.companion.isDefined, "test.templates.Base.T should have a pseudo-companion object")
+ testDiagram(BaseT, BaseT.inheritanceDiagram, 2, 1)
+
+ val Api = main._trait("Api")
+ assert(Api.members.filter(_.inDefinitionTemplates.head == Api).length == 2, Api.members.filter(_.inDefinitionTemplates.head == Api).length + " == 2") // FooApi and override type T
+ assert(Api.members.collect{case d: DocTemplateEntity => d}.length == 5, Api.members.collect{case d: DocTemplateEntity => d}.length == 5)
+ testDiagram(Api, Api.contentDiagram, 3, 2)
+
+ val ApiT = Api._absTypeTpl("T")
+ val FooApi = Api._trait("FooApi")
+ assert(ApiT.members.filter(_.inDefinitionTemplates.head == Api).length == 0, ApiT.members.filter(_.inDefinitionTemplates.head == Api).length + " == 0")
+ assert(ApiT.members.map(_.name).sorted == FooApi.members.map(_.name).sorted, ApiT.members.map(_.name).sorted + " == " + FooApi.members.map(_.name).sorted)
+ assert(ApiT.companion.isDefined, "test.templates.Api.T should have a pseudo-companion object")
+ testDiagram(ApiT, ApiT.inheritanceDiagram, 2, 1)
+ }
+} \ No newline at end of file