diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala | 150 |
1 files changed, 120 insertions, 30 deletions
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) |