summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorVlad Ureche <vlad.ureche@gmail.com>2012-06-16 04:23:43 +0200
committerVlad Ureche <vlad.ureche@gmail.com>2012-07-16 23:41:43 +0200
commitf916434c119289773e5aad88c633c30f68a12e14 (patch)
tree12f8c6a52d480454d4cefb0d7a10975b39c3d3c5 /src/compiler/scala/tools
parentfcbdc1725c6fcd65a071709408ef75097f487cb7 (diff)
downloadscala-f916434c119289773e5aad88c633c30f68a12e14.tar.gz
scala-f916434c119289773e5aad88c633c30f68a12e14.tar.bz2
scala-f916434c119289773e5aad88c633c30f68a12e14.zip
SI-3314 SI-4888 Scaladoc: Relative type prefixes
And adds support for linking to class members, only usable from the model factory now, so no links to members from the doc comment yet, sorry. But it fixes the Enumeration problem once and for all! Also corrected the inTpl for members obtained by implicit conversions, so they're in the correct template and the comment variable expansion is done from the correct (but different) template. Review by @kzys.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala10
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/Page.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Index.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala42
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/Entity.scala17
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala150
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala27
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala5
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala2
12 files changed, 165 insertions, 102 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
index 51c5793d46..18cc65092b 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala
@@ -138,7 +138,7 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
if (!(written contains tpl)) {
writeForThis(new page.Template(universe, diagramGenerator, tpl))
written += tpl
- tpl.templates map writeTemplate
+ tpl.templates collect { case d: DocTemplateEntity => d } map writeTemplate
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
index 4a1a8cf898..af5e90083e 100644
--- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -155,12 +155,18 @@ abstract class HtmlPage extends Page { thisPage =>
def toLinksIn(inPos: Int, starts: List[Int]): NodeSeq = {
val (tpl, width) = tpe.refEntity(inPos)
(tpl match {
- case dtpl:DocTemplateEntity if hasLinks =>
+ case LinkToTpl(dtpl:DocTemplateEntity) if hasLinks =>
<a href={ relativeLinkTo(dtpl) } class="extype" name={ dtpl.qualifiedName }>{
string.slice(inPos, inPos + width)
}</a>
- case tpl =>
+ case LinkToTpl(tpl) =>
<span class="extype" name={ tpl.qualifiedName }>{ string.slice(inPos, inPos + width) }</span>
+ case LinkToMember(mbr, inTpl) if hasLinks =>
+ <a href={ relativeLinkTo(inTpl) + "#" + mbr.signature } class="extmbr" name={ mbr.qualifiedName }>{
+ string.slice(inPos, inPos + width)
+ }</a>
+ case LinkToMember(mbr, inTpl) =>
+ <span class="extmbr" name={ mbr.qualifiedName }>{ string.slice(inPos, inPos + width) }</span>
}) ++ toLinksOut(inPos + width, starts.tail)
}
if (hasLinks)
diff --git a/src/compiler/scala/tools/nsc/doc/html/Page.scala b/src/compiler/scala/tools/nsc/doc/html/Page.scala
index 5e3ab87ccd..08df26e745 100644
--- a/src/compiler/scala/tools/nsc/doc/html/Page.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/Page.scala
@@ -48,7 +48,7 @@ abstract class Page {
* @param generator The generator that is writing this page. */
def writeFor(site: HtmlFactory): Unit
- def docEntityKindToString(ety: DocTemplateEntity) =
+ def docEntityKindToString(ety: TemplateEntity) =
if (ety.isTrait) "trait"
else if (ety.isCaseClass) "case class"
else if (ety.isClass) "class"
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
index 0e894a03bf..ba48bf3f9b 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala
@@ -61,7 +61,9 @@ class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage {
}
<ol class="templates">{
val tpls: Map[String, Seq[DocTemplateEntity]] =
- (pack.templates filter (t => !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) )) groupBy (_.name)
+ (pack.templates collect {
+ case t: DocTemplateEntity if !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) => t
+ }) groupBy (_.name)
val placeholderSeq: NodeSeq = <div class="placeholder"></div>
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala
index 2b68ac2937..e1ab479f9d 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/IndexScript.scala
@@ -62,7 +62,9 @@ class IndexScript(universe: doc.Universe, index: doc.Index) extends Page {
def allPackagesWithTemplates = {
Map(allPackages.map((key) => {
- key -> key.templates.filter(t => !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName))
+ key -> key.templates.collect {
+ case t: DocTemplateEntity if !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) => t
+ }
}) : _*)
}
}
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 0d0410c7e2..47834e542c 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
@@ -238,44 +238,12 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
</body>
}
- def boundsToString(hi: Option[TypeEntity], lo: Option[TypeEntity]): String = {
- def bound0(bnd: Option[TypeEntity], pre: String): String = bnd match {
- case None => ""
- case Some(tpe) => pre ++ tpe.toString
- }
- bound0(hi, "<:") ++ bound0(lo, ">:")
- }
-
- def tparamsToString(tpss: List[TypeParam]): String = {
- if (tpss.isEmpty) "" else {
- def tparam0(tp: TypeParam): String =
- tp.variance + tp.name + boundsToString(tp.hi, tp.lo)
- def tparams0(tpss: List[TypeParam]): String = (tpss: @unchecked) match {
- case tp :: Nil => tparam0(tp)
- case tp :: tps => tparam0(tp) ++ ", " ++ tparams0(tps)
- }
- "[" + tparams0(tpss) + "]"
- }
- }
-
- def defParamsToString(d: MemberEntity with Def): String = {
- val paramLists: List[String] =
- if (d.valueParams.isEmpty) Nil
- else d.valueParams map (ps => ps map (_.resultType.name) mkString ("(",",",")"))
-
- tparamsToString(d.typeParams) + paramLists.mkString
- }
-
def memberToHtml(mbr: MemberEntity, inTpl: DocTemplateEntity): NodeSeq = {
- val defParamsString = mbr match {
- case d:MemberEntity with Def => defParamsToString(d)
- case _ => ""
- }
val memberComment = memberToCommentHtml(mbr, inTpl, false)
<li name={ mbr.definitionName } visbl={ if (mbr.visibility.isProtected) "prt" else "pub" }
data-isabs={ mbr.isAbstract.toString }
fullComment={ if(memberComment.filter(_.label=="div").isEmpty) "no" else "yes" }>
- <a id={ mbr.name +defParamsString +":"+ mbr.resultType.name}/>
+ <a id={ mbr.signature }/>
{ signature(mbr, false) }
{ memberComment }
</li>
@@ -650,6 +618,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
def kindToString(mbr: MemberEntity): String = {
mbr match {
case tpl: DocTemplateEntity => docEntityKindToString(tpl)
+ case tpl: NoDocTemplateMemberEntity => docEntityKindToString(tpl)
case ctor: Constructor => "new"
case tme: MemberEntity =>
( if (tme.isDef) "def"
@@ -850,18 +819,13 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
val link = relativeLinkTo(mbr)
myXml ++= <span class="name"><a href={link}>{str.substring(from, to)}</a></span>
case mbr: MemberEntity =>
- val anchor = "#" + mbr.name + defParamsString(mbr) + ":" + mbr.resultType.name
+ val anchor = "#" + mbr.signature
val link = relativeLinkTo(mbr.inTemplate)
myXml ++= <span class="name"><a href={link ++ anchor}>{str.substring(from, to)}</a></span>
}
index = to
}
}
- // function used in the MemberEntity case above
- def defParamsString(mbr: Entity):String = mbr match {
- case d:MemberEntity with Def => defParamsToString(d)
- case _ => ""
- }
if (index <= length-1)
myXml ++= codeStringToXml(str.substring(index, length ))
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 dc6f941c30..8648fdb0a1 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
@@ -74,7 +74,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator {
def textTypeEntity(text: String) =
new TypeEntity {
val name = text
- def refEntity: SortedMap[Int, (TemplateEntity, Int)] = SortedMap()
+ def refEntity: SortedMap[Int, (LinkTo, Int)] = SortedMap()
}
// it seems dot chokes on node names over 8000 chars, so let's limit the size of the string
diff --git a/src/compiler/scala/tools/nsc/doc/model/Entity.scala b/src/compiler/scala/tools/nsc/doc/model/Entity.scala
index 2901daafd6..4ab77b356b 100644
--- a/src/compiler/scala/tools/nsc/doc/model/Entity.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/Entity.scala
@@ -53,6 +53,9 @@ trait Entity {
/** The kind of the entity */
def kind: String
+
+ /** Whether or not the template was defined in a package object */
+ def inPackageObject: Boolean
}
object Entity {
@@ -91,9 +94,6 @@ trait TemplateEntity extends Entity {
/** Whether this template is a case class. */
def isCaseClass: Boolean
- /** Whether or not the template was defined in a package object */
- def inPackageObject: Boolean
-
/** The self-type of this template, if it differs from the template type. */
def selfType : Option[TypeEntity]
@@ -183,7 +183,11 @@ trait MemberEntity extends Entity {
/** If this member originates from an implicit conversion, we set the implicit information to the correct origin */
def byConversion: Option[ImplicitConversion]
+
+ /** The identity of this member, used for linking */
+ def signature: String
}
+
object MemberEntity {
// Oh contravariance, contravariance, wherefore art thou contravariance?
// Note: the above works for both the commonly misunderstood meaning of the line and the real one.
@@ -205,7 +209,10 @@ trait NoDocTemplate extends TemplateEntity {
def kind = "<no doc>"
}
-/** TODO: Document */
+/** An inherited template that was not documented in its original owner - example:
+ * in classpath: trait T { class C } -- T (and implicitly C) are not documented
+ * in the source: trait U extends T -- C appears in U as a NoDocTemplateMemberImpl
+ * -- that is, U has a member for it but C doesn't get its own page */
trait NoDocTemplateMemberEntity extends TemplateEntity with MemberEntity {
def kind = "<no doc, mbr>"
}
@@ -253,7 +260,7 @@ trait DocTemplateEntity extends TemplateEntity with MemberEntity {
/** All templates that are members of this template. If this template is a package, only templates for which
* documentation is available in the universe (`DocTemplateEntity`) are listed. */
- def templates: List[DocTemplateEntity]
+ def templates: List[TemplateEntity with MemberEntity]
/** All methods that are members of this template. */
def methods: List[Def]
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index 9fa6619e9f..2efbfbe43c 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -83,6 +83,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def toRoot: List[EntityImpl] = this :: inTpl.toRoot
def qualifiedName = name
def annotations = sym.annotations.map(makeAnnotation)
+ def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject
}
trait TemplateImpl extends EntityImpl with TemplateEntity {
@@ -96,11 +97,25 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def isRootPackage = false
def ownType = makeType(sym.tpe, this)
def selfType = if (sym.thisSym eq sym) None else Some(makeType(sym.thisSym.typeOfThis, this))
- def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject
}
abstract class MemberImpl(sym: Symbol, implConv: ImplicitConversionImpl, inTpl: DocTemplateImpl) extends EntityImpl(sym, inTpl) with MemberEntity {
- lazy val comment = if (inTpl != null) thisFactory.comment(sym, inTpl) else None
+ lazy val comment = {
+ val commentTpl =
+ /* Variable precendence order for implicitly added members: Take the variable defifinitions from ...
+ * 1. the target of the implicit conversion
+ * 2. the definition template (owner)
+ * 3. the current template
+ */
+ if (implConv != null) findTemplateMaybe(implConv.toType.typeSymbol) match {
+ case Some(d) if d != makeRootPackage => d //in case of NoSymbol, it will give us the root package
+ case _ => findTemplateMaybe(sym.owner) match {
+ case Some(d) if d != makeRootPackage => d //in case of NoSymbol, it will give us the root package
+ case _ => inTpl
+ }
+ } else inTpl
+ if (commentTpl != null) thisFactory.comment(sym, commentTpl) else None
+ }
override def inTemplate = inTpl
override def toRoot: List[MemberImpl] = this :: inTpl.toRoot
def inDefinitionTemplates = this match {
@@ -189,6 +204,30 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
sym.isAbstractClass || sym.isAbstractType) && !sym.isSynthetic
def isTemplate = false
def byConversion = if (implConv ne null) Some(implConv) else None
+ lazy val signature = {
+
+ val defParamsString = this match {
+ case d: MemberEntity with Def =>
+ val paramLists: List[String] =
+ if (d.valueParams.isEmpty) Nil
+ else d.valueParams map (ps => ps map (_.resultType.name) mkString ("(",",",")"))
+
+ val tParams = if (d.typeParams.isEmpty) "" else {
+ def boundsToString(hi: Option[TypeEntity], lo: Option[TypeEntity]): String = {
+ def bound0(bnd: Option[TypeEntity], pre: String): String = bnd match {
+ case None => ""
+ case Some(tpe) => pre ++ tpe.toString
+ }
+ bound0(hi, "<:") ++ bound0(lo, ">:")
+ }
+ "[" + d.typeParams.map(tp => tp.variance + tp.name + boundsToString(tp.hi, tp.lo)).mkString(", ") + "]"
+ }
+
+ tParams + paramLists.mkString
+ case _ => ""
+ }
+ name + defParamsString +":"+ resultType.name
+ }
}
/** A template that is not documented at all. The class is instantiated during lookups, to indicate that the class
@@ -198,7 +237,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
assert(modelFinished)
assert(!(noDocTemplatesCache isDefinedAt sym))
noDocTemplatesCache += (sym -> this)
-
def isDocTemplate = false
}
@@ -209,7 +247,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
*/
class NoDocTemplateMemberImpl(sym: Symbol, inTpl: DocTemplateImpl) extends MemberImpl(sym, null, inTpl) with TemplateImpl with HigherKindedImpl with NoDocTemplateMemberEntity {
assert(modelFinished)
-
+ // no templates cache for this class, each owner gets its own instance
+ override def isTemplate = true
def isDocTemplate = false
lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name)
}
@@ -330,7 +369,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
// all the members that are documentented PLUS the members inherited by implicit conversions
var members: List[MemberImpl] = ownMembers
- def templates = members collect { case c: DocTemplateEntity => c }
+ def templates = members collect { case c: TemplateEntity with MemberEntity => c }
def methods = members collect { case d: Def => d }
def values = members collect { case v: Val => v }
def abstractTypes = members collect { case t: AbstractType => t }
@@ -348,7 +387,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
case _ =>
}
- members :::= memberSymsLazy.map(modelCreation.createLazyTemplateMember(_, inTpl))
+ members :::= memberSymsLazy.map(modelCreation.createLazyTemplateMember(_, this))
// compute linearization to register subclasses
linearization
@@ -411,9 +450,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
abstract class NonTemplateMemberImpl(sym: Symbol, implConv: ImplicitConversionImpl, inTpl: DocTemplateImpl) extends MemberImpl(sym, implConv, inTpl) with NonTemplateMemberEntity {
override def qualifiedName = optimize(inTemplate.qualifiedName + "#" + name)
- lazy val definitionName =
- if (implConv == null) optimize(inDefinitionTemplates.head.qualifiedName + "#" + name)
- else optimize(implConv.conversionQualifiedName + "#" + name)
+ lazy val definitionName = {
+ // this contrived name is here just to satisfy some older tests -- if you decide to remove it, be my guest, and
+ // also remove property("package object") from test/scaladoc/scalacheck/HtmlFactoryTest.scala so you don't break
+ // the test suite...
+ val packageObject = if (inPackageObject) ".package" else ""
+ if (implConv == null) optimize(inDefinitionTemplates.head.qualifiedName + packageObject + "#" + name)
+ else optimize(implConv.conversionQualifiedName + packageObject + "#" + name)
+ }
def isUseCase = sym.isSynthetic
def isBridge = sym.isBridge
}
@@ -461,7 +505,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
case ObjectClass =>
normalizeTemplate(AnyRefClass)
case _ if aSym.isPackageObject =>
- aSym
+ normalizeTemplate(aSym.owner)
case _ if aSym.isModuleClass =>
normalizeTemplate(aSym.sourceModule)
case _ =>
@@ -501,6 +545,7 @@ 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))
new DocTemplateImpl(bSym, inTpl) with Object
else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait))
@@ -566,6 +611,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
* - NoDocTemplateEntity (created in makeTemplate)
*/
def createLazyTemplateMember(aSym: Symbol, inTpl: DocTemplateImpl): MemberImpl = {
+
+ // Code is duplicate because the anonymous classes are created statically
+ def createNoDocMemberTemplate(bSym: Symbol, inTpl: DocTemplateImpl): NoDocTemplateMemberImpl = {
+ assert(modelFinished) // only created AFTER the model is finished
+ new NoDocTemplateMemberImpl(bSym, inTpl)
+ }
+
assert(modelFinished)
val bSym = normalizeTemplate(aSym)
@@ -579,7 +631,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
mbrs.head
case _ =>
// move the class completely to the new location
- new NoDocTemplateMemberImpl(aSym, inTpl)
+ createNoDocMemberTemplate(bSym, inTpl)
}
}
}
@@ -690,7 +742,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
docTemplatesCache.get(normalizeTemplate(aSym))
}
- def makeTemplate(aSym: Symbol): TemplateImpl = {
+ def makeTemplate(aSym: Symbol): TemplateImpl = makeTemplate(aSym, None)
+
+ def makeTemplate(aSym: Symbol, inTpl: Option[TemplateImpl]): TemplateImpl = {
assert(modelFinished)
def makeNoDocTemplate(aSym: Symbol, inTpl: TemplateImpl): NoDocTemplateImpl = {
@@ -706,7 +760,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
dtpl
case None =>
val bSym = normalizeTemplate(aSym)
- makeNoDocTemplate(bSym, makeTemplate(bSym.owner))
+ makeNoDocTemplate(bSym, if (inTpl.isDefined) inTpl.get else makeTemplate(bSym.owner))
}
}
@@ -797,10 +851,10 @@ 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 {
case RefinedType(parents, defs) =>
- val ignoreParents = Set[Symbol](AnyRefClass, ObjectClass)
+ val ignoreParents = Set[Symbol](AnyClass, AnyRefClass, ObjectClass)
val filtParents =
// we don't want to expose too many links to AnyRef, that will just be redundant information
- if (tpl.isDefined && (!tpl.get.isObject && parents.length < 2))
+ if (tpl.isDefined && { val sym = tpl.get.sym; (!sym.isModule && parents.length < 2) || (sym == AnyValClass) || (sym == AnyRefClass) || (sym == AnyClass) })
parents
else
parents.filterNot((p: Type) => ignoreParents(p.typeSymbol))
@@ -819,7 +873,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
def createTypeEntity = new TypeEntity {
private val nameBuffer = new StringBuilder
- private var refBuffer = new immutable.TreeMap[Int, (TemplateEntity, Int)]
+ private var refBuffer = new immutable.TreeMap[Int, (LinkTo, Int)]
private def appendTypes0(types: List[Type], sep: String): Unit = types match {
case Nil =>
case tp :: Nil =>
@@ -862,15 +916,56 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
// if (!preSym.printWithoutPrefix) {
// nameBuffer append stripPrefixes.foldLeft(pre.prefixString)(_ stripPrefix _)
// }
+
+ // SI-3314/SI-4888: Classes, Traits and Types can be inherited from a template to another:
+ // class Enum { abstract class Value }
+ // class Day extends Enum { object Mon extends Value /*...*/ }
+ // ===> in such cases we have two options:
+ // (0) if there's no inheritance taking place (Enum#Value) we can link to the template directly
+ // (1) if we generate the doc template for Day, we can link to the correct member
+ // (2) if we don't generate the doc template, we should at least indicate the correct prefix in the tooltip
val bSym = normalizeTemplate(aSym)
- if (bSym.isNonClassType && bSym != AnyRefClass) {
- nameBuffer append bSym.decodedName
- } else {
- val tpl = makeTemplate(bSym)
- val pos0 = nameBuffer.length
- refBuffer += pos0 -> (tpl, tpl.name.length)
- nameBuffer append tpl.name
- }
+ val owner =
+ if ((preSym != NoSymbol) && /* it needs a prefix */
+ (preSym != bSym.owner) && /* prefix is different from owner */
+ // ((preSym != inTpl.sym) && /* prevent prefixes from being shown inside the defining class */
+ // (preSym != inTpl.sym.moduleClass)) && /* or object */
+ (aSym == bSym)) /* normalization doesn't play tricks on us */
+ preSym
+ else
+ bSym.owner
+
+ val bTpl = findTemplateMaybe(bSym)
+ val link =
+ if (owner == bSym.owner && bTpl.isDefined)
+ // (0) the owner's class is linked AND has a template - lovely
+ LinkToTpl(bTpl.get)
+ else {
+ val oTpl = findTemplateMaybe(owner)
+ val bMbr = oTpl.map(findMember(bSym, _))
+ if (oTpl.isDefined && bMbr.isDefined && bMbr.get.isDefined)
+ // (1) the owner's class
+ LinkToMember(bMbr.get.get, oTpl.get) //ugh
+ else
+ // (2) if we still couldn't find the owner, make a noDocTemplate for everything (in the correct owner!)
+ LinkToTpl(makeTemplate(bSym, Some(makeTemplate(owner))))
+ }
+
+ // TODO: The name might include a prefix, take care of that!
+ val name = bSym.nameString
+ val pos0 = nameBuffer.length
+ refBuffer += pos0 -> ((link, name.length))
+ nameBuffer append name
+
+ // if (bSym.isNonClassType && bSym != AnyRefClass) {
+ // nameBuffer append bSym.decodedName
+ // } else {
+ // val tpl = makeTemplate(bSym)
+ // val pos0 = nameBuffer.length
+ // refBuffer += pos0 -> ((LinkToTpl(tpl), tpl.name.length))
+ // nameBuffer append tpl.name
+ // }
+
if (!targs.isEmpty) {
nameBuffer append '['
appendTypes0(targs, ", ")
@@ -949,12 +1044,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
* (1) sourceModule
* (2) you get out of owners with .owner
*/
- normalizeTemplate(aSym) match {
- case bSym if bSym.isPackageObject =>
- normalizeOwner(bSym.owner)
- case bSym =>
- bSym
- }
+ normalizeTemplate(aSym)
def inOriginalOnwer(aSym: Symbol, inTpl: TemplateImpl): Boolean =
normalizeOwner(aSym.owner) == normalizeOwner(inTpl.sym)
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
index 8cbf2ac1b6..493ad3d831 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala
@@ -408,25 +408,14 @@ trait ModelFactoryImplicitSupport {
debug("")
memberSyms.flatMap({ aSym =>
- makeTemplate(aSym.owner) match {
- case d: DocTemplateImpl =>
- // we can't just pick up nodes from the previous template, although that would be very convenient:
- // they need the byConversion field to be attached to themselves -- this is design decision I should
- // revisit soon
- //
- // d.ownMembers.collect({
- // // it's either a member or has a couple of usecases it's hidden behind
- // case m: MemberImpl if m.sym == aSym =>
- // m // the member itself
- // case m: MemberImpl if m.useCaseOf.isDefined && m.useCaseOf.get.asInstanceOf[MemberImpl].sym == aSym =>
- // m.useCaseOf.get.asInstanceOf[MemberImpl] // the usecase
- // })
- makeMember(aSym, this, d)
- case _ =>
- // should only happen if the code for this template is not part of the scaladoc run =>
- // members won't have any comments
- makeMember(aSym, this, inTpl)
- }
+ // we can't just pick up nodes from the original template, although that would be very convenient:
+ // they need the byConversion field to be attached to themselves and the types to be transformed by
+ // asSeenFrom
+
+ // at the same time, the member itself is in the inTpl, not in the new template -- but should pick up
+ // variables from the old template. Ugly huh? We'll always create the member inTpl, but it will change
+ // the template when expanding variables in the comment :)
+ makeMember(aSym, this, inTpl)
})
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
index 67e955f613..a16e99bf06 100644
--- a/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/TypeEntity.scala
@@ -9,6 +9,9 @@ package model
import scala.collection._
+abstract sealed class LinkTo
+case class LinkToTpl(tpl: TemplateEntity) extends LinkTo
+case class LinkToMember(mbr: MemberEntity, inTpl: DocTemplateEntity) extends LinkTo
/** A type. Note that types and templates contain the same information only for the simplest types. For example, a type
* defines how a template's type parameters are instantiated (as in `List[Cow]`), what the template's prefix is
@@ -21,7 +24,7 @@ abstract class TypeEntity {
/** Maps which parts of this type's name reference entities. The map is indexed by the position of the first
* character that reference some entity, and contains the entity and the position of the last referenced
* character. The referenced character ranges do not to overlap or nest. The map is sorted by position. */
- def refEntity: SortedMap[Int, (TemplateEntity, Int)]
+ def refEntity: SortedMap[Int, (LinkTo, Int)]
/** The human-readable representation of this type. */
override def toString = name
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 1a8ad193aa..4b05da98cd 100644
--- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala
@@ -32,7 +32,7 @@ trait DiagramFactory extends DiagramDirectiveParser {
def normalNode(sym: Symbol) =
NormalNode(makeTemplate(sym).ownType, Some(makeTemplate(sym)))
def aggregationNode(text: String) =
- NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (TemplateEntity, Int)]() }, None)
+ NormalNode(new TypeEntity { val name = text; val refEntity = SortedMap[Int, (LinkTo, Int)]() }, None)
/** Create the inheritance diagram for this template */
def makeInheritanceDiagram(tpl: DocTemplateImpl): Option[Diagram] = {