summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala')
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala162
1 files changed, 107 insertions, 55 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index e2a25d7ea4..e36df22435 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -7,13 +7,14 @@ package model
import comment._
import scala.collection._
+import scala.util.matching.Regex
import symtab.Flags
import model.{ RootPackage => RootPackageEntity }
/** This trait extracts all required information for documentation from compilation units */
-class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory =>
+class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory with TreeFactory =>
import global._
import definitions.{ ObjectClass, ScalaObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyRefClass }
@@ -22,13 +23,18 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def templatesCount = templatesCache.size - droppedPackages
private var modelFinished = false
+ private var universe: Universe = null
/** */
def makeModel: Universe = {
- val rootPackage =
- makeRootPackage getOrElse { throw new Error("no documentable class found in compilation units") }
- val universe = new Universe(settings, rootPackage)
+ val universe = new Universe { thisUniverse =>
+ thisFactory.universe = thisUniverse
+ val settings = thisFactory.settings
+ val rootPackage =
+ makeRootPackage getOrElse { throw new Error("no documentable class found in compilation units") }
+ }
modelFinished = true
+ thisFactory.universe = null
universe
}
@@ -49,20 +55,24 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
/** Provides a default implementation for instances of the `Entity` type. */
abstract class EntityImpl(val sym: Symbol, inTpl: => TemplateImpl) extends Entity {
val name = optimize(sym.nameString)
- def inTemplate = inTpl
+ def inTemplate: TemplateImpl = inTpl
def toRoot: List[EntityImpl] = this :: inTpl.toRoot
def qualifiedName = name
+ val universe = thisFactory.universe
}
/** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a
* `SymbolicEntity` to access the compiler symbol that underlies the entity. */
trait TemplateImpl extends EntityImpl with TemplateEntity {
- override def qualifiedName = if (inTemplate.isRootPackage) name else optimize(inTemplate.qualifiedName + "." + name)
+ override def qualifiedName: String =
+ if (inTemplate.isRootPackage) name else optimize(inTemplate.qualifiedName + "." + name)
def isPackage = sym.isPackage
def isTrait = sym.isTrait
def isClass = sym.isClass && !sym.isTrait
def isObject = sym.isModule && !sym.isPackage
+ def isCaseClass = sym.isClass && sym.hasFlag(Flags.CASE)
def isRootPackage = false
+ def selfType = if (sym.thisSym eq sym) None else Some(makeType(sym.thisSym.typeOfThis, this))
}
/** Provides a default implementation for instances of the `WeakTemplateEntity` type. It must be instantiated as a
@@ -117,7 +127,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def inheritedFrom =
if (inTemplate.sym == this.sym.owner || inTemplate.sym.isPackage) Nil else
makeTemplate(this.sym.owner) :: (sym.allOverriddenSymbols map { os => makeTemplate(os.owner) })
- def resultType = makeType(sym.tpe.finalResultType, inTemplate, sym)
+ def resultType = {
+ def resultTpe(tpe: Type): Type = tpe match { // similar to finalResultType, except that it leaves singleton types alone
+ case PolyType(_, res) => resultTpe(res)
+ case MethodType(_, res) => resultTpe(res)
+ case _ => tpe
+ }
+ makeType(resultTpe(sym.tpe), inTemplate, sym)
+ }
def isDef = false
def isVal = false
def isLazyVal = false
@@ -126,6 +143,9 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def isConstructor = false
def isAliasType = false
def isAbstractType = false
+ def isAbstract =
+ ((!sym.isTrait && ((sym hasFlag Flags.ABSTRACT) || (sym hasFlag Flags.DEFERRED))) ||
+ sym.isAbstractClass || sym.isAbstractType) && !sym.isSynthetic
def isTemplate = false
}
@@ -137,7 +157,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
* * The owner of the template (as a full template);
* * All ancestors of the template (as weak templates);
* * All non-package members (including other templates, as full templates). */
- abstract class DocTemplateImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with DocTemplateEntity {
+ abstract class DocTemplateImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends MemberImpl(sym, inTpl) with TemplateImpl with HigherKindedImpl with DocTemplateEntity {
//if (inTpl != null) println("mbr " + sym + " in " + (inTpl.toRoot map (_.sym)).mkString(" > "))
templatesCache += (sym -> this)
lazy val definitionName = optimize(inDefinitionTemplates.head.qualifiedName + "." + name)
@@ -151,26 +171,41 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
}
if (!settings.docsourceurl.isDefault)
inSource map { case (file, _) =>
- new java.net.URL(settings.docsourceurl.value + "/" + fixPath(file.path).replaceFirst("^" + assumedSourceRoot, ""))
+ val filePath = fixPath(file.path).replaceFirst("^" + assumedSourceRoot, "").stripSuffix(".scala")
+ val tplOwner = this.inTemplate.qualifiedName
+ val tplName = this.name
+ val patches = new Regex("""€\{(FILE_PATH|TPL_OWNER|TPL_NAME)\}""")
+ val patchedString = patches.replaceAllIn(settings.docsourceurl.value, { m => m.group(1) match {
+ case "FILE_PATH" => filePath
+ case "TPL_OWNER" => tplOwner
+ case "TPL_NAME" => tplName
+ }
+ })
+ new java.net.URL(patchedString)
}
else None
}
- def typeParams = if (sym.isClass) sym.typeParams map (makeTypeParam(_, this)) else Nil
- def parentTemplates = sym.info.parents map { x: Type => makeTemplate(x.typeSymbol) }
- def parentType =
- if (sym.isPackage) None else
- Some(makeType(RefinedType(sym.tpe.parents filter (_ != ScalaObjectClass.tpe), EmptyScope)))
- val linearization = {
- sym.info.parents map { prt =>
- makeTemplate(prt.typeSymbol) match {
+ def parentType = {
+ if (sym.isPackage) None else {
+ val tps =
+ (sym.tpe.parents filter (_ != ScalaObjectClass.tpe)) map { _.asSeenFrom(sym.thisType, sym) }
+ Some(makeType(RefinedType(tps, EmptyScope), inTpl))
+ }
+ }
+ val linearization: List[(TemplateEntity, TypeEntity)] = {
+ val acs = sym.ancestors filter { _ != ScalaObjectClass }
+ val tps = acs map { cls => makeType(sym.info.baseType(cls), this) }
+ val tpls = acs map { makeTemplate(_) }
+ tpls map {
case dtpl: DocTemplateImpl => dtpl.registerSubClass(this)
case _ =>
- }
}
- sym.ancestors filter (_ != ScalaObjectClass) map { makeTemplate(_) }
+ tpls zip tps
}
+ def linearizationTemplates = linearization map { _._1 }
+ def linearizationTypes = linearization map { _._2 }
private lazy val subClassesCache = mutable.Buffer.empty[DocTemplateEntity]
- def registerSubClass(sc: DocTemplateEntity) = {
+ def registerSubClass(sc: DocTemplateEntity): Unit = {
assert(subClassesCache != null)
subClassesCache += sc
}
@@ -188,7 +223,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def isDocTemplate = true
def companion = sym.companionSymbol match {
case NoSymbol => None
- case comSym => Some(makeDocTemplate(comSym, inTpl))
+ case comSym if !isEmptyJavaObject(comSym) => Some(makeDocTemplate(comSym, inTpl))
+ case _ => None
}
}
@@ -213,21 +249,28 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
}}
}
- abstract class ParameterImpl(sym: Symbol, inTpl: => DocTemplateImpl) extends EntityImpl(sym, inTpl) with ParameterEntity {
+ abstract class ParameterImpl(sym: Symbol, inTpl: => TemplateImpl) extends EntityImpl(sym, inTpl) with ParameterEntity {
override def inTemplate = inTpl
}
private trait TypeBoundsImpl extends EntityImpl {
- def lo = sym.info.normalize match {
- case TypeBounds(lo, hi) if lo.typeSymbol != NothingClass => Some(makeType(lo, inTemplate, sym))
+ def lo = sym.info.bounds match {
+ case TypeBounds(lo, hi) if lo.typeSymbol != NothingClass =>
+ Some(makeType(appliedType(lo, sym.info.typeParams map {_.tpe}), inTemplate))
case _ => None
}
- def hi = sym.info.normalize match {
- case TypeBounds(lo, hi) if hi.typeSymbol != AnyClass => Some(makeType(hi, inTemplate, sym))
+ def hi = sym.info.bounds match {
+ case TypeBounds(lo, hi) if hi.typeSymbol != AnyClass =>
+ Some(makeType(appliedType(hi, sym.info.typeParams map {_.tpe}), inTemplate))
case _ => None
}
}
+ trait HigherKindedImpl extends EntityImpl with HigherKinded {
+ def typeParams =
+ sym.typeParams map (makeTypeParam(_, inTemplate))
+ }
+
/* ============== MAKER METHODS ============== */
/** */
@@ -312,18 +355,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
else if (bSym.isModule || (bSym.isAliasType && bSym.tpe.typeSymbol.isModule))
new DocTemplateImpl(bSym, minimumInTpl) with Object
else if (bSym.isTrait || (bSym.isAliasType && bSym.tpe.typeSymbol.isTrait))
- new DocTemplateImpl(bSym, minimumInTpl) with Trait {
- def valueParams =
- List(sym.constrParamAccessors map (makeValueParam(_, this)))
- }
+ new DocTemplateImpl(bSym, minimumInTpl) with Trait
else if (bSym.isClass || (bSym.isAliasType && bSym.tpe.typeSymbol.isClass))
new DocTemplateImpl(bSym, minimumInTpl) with Class {
def valueParams =
- List(sym.constrParamAccessors map (makeValueParam(_, this)))
+ // we don't want params on a class (non case class) signature
+ if (isCaseClass) List(sym.constrParamAccessors map (makeValueParam(_, this)))
+ else List.empty
val constructors =
members collect { case d: Constructor => d }
def primaryConstructor = constructors find { _.isPrimary }
- def isCaseClass = sym.isClass && sym.hasFlag(Flags.CASE)
}
else
throw new Error("'" + bSym + "' that isn't a class, trait or object cannot be built as a documentable template")
@@ -342,10 +383,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
override def isVar = true
})
else if (bSym.isMethod && !bSym.isGetterOrSetter && !bSym.isConstructor && !bSym.isModule)
- Some(new NonTemplateParamMemberImpl(bSym, inTpl) with Def {
+ Some(new NonTemplateParamMemberImpl(bSym, inTpl) with HigherKindedImpl with Def {
override def isDef = true
- def typeParams =
- sym.tpe.typeParams map (makeTypeParam(_, inTpl))
})
else if (bSym.isConstructor)
Some(new NonTemplateParamMemberImpl(bSym, inTpl) with Constructor {
@@ -357,13 +396,13 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
override def isVal = true
})
else if (bSym.isAbstractType)
- Some(new NonTemplateMemberImpl(bSym, inTpl) with TypeBoundsImpl with AbstractType {
+ Some(new NonTemplateMemberImpl(bSym, inTpl) with TypeBoundsImpl with HigherKindedImpl with AbstractType {
override def isAbstractType = true
})
else if (bSym.isAliasType)
- Some(new NonTemplateMemberImpl(bSym, inTpl) with AliasType {
+ Some(new NonTemplateMemberImpl(bSym, inTpl) with HigherKindedImpl with AliasType {
override def isAliasType = true
- def alias = makeType(sym.tpe, inTpl, sym)
+ def alias = makeType(appliedType(sym.tpe, sym.info.typeParams map {_.tpe}).normalize, inTpl, sym)
})
else if (bSym.isPackage)
inTpl match { case inPkg: PackageImpl => makePackage(bSym, inPkg) }
@@ -385,8 +424,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
}
/** */
- def makeTypeParam(aSym: Symbol, inTpl: => DocTemplateImpl): TypeParam = {
- new ParameterImpl(aSym, inTpl) with TypeBoundsImpl with TypeParam {
+ def makeTypeParam(aSym: Symbol, inTpl: => TemplateImpl): TypeParam =
+ new ParameterImpl(aSym, inTpl) with TypeBoundsImpl with HigherKindedImpl with TypeParam {
def isTypeParam = true
def isValueParam = false
def variance: String = {
@@ -395,7 +434,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
else ""
}
}
- }
/** */
def makeValueParam(aSym: Symbol, inTpl: => DocTemplateImpl): ValueParam = {
@@ -414,7 +452,8 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
(currentRun.units filter (_.source.file == aSym.sourceFile)).toList match {
case List(unit) =>
(unit.body find (_.symbol == aSym)) match {
- case Some(ValDef(_,_,_,rhs)) => Some(rhs.toString)
+ case Some(ValDef(_,_,_,rhs)) =>
+ Some(makeTree(rhs))
case _ => None
}
case _ => None
@@ -426,14 +465,21 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
}
/** */
- def makeType(aType: Type, seeInTpl: => TemplateImpl, dclSym: Symbol): TypeEntity = {
+ def makeType(aType: Type, inTpl: => TemplateImpl, dclSym: Symbol): TypeEntity = {
def ownerTpl(sym: Symbol): Symbol =
if (sym.isClass || sym.isModule || sym == NoSymbol) sym else ownerTpl(sym.owner)
- makeType(aType.asSeenFrom(seeInTpl.sym.thisType, ownerTpl(dclSym)))
+ val tpe =
+ if (thisFactory.settings.useStupidTypes.value) aType else {
+ def ownerTpl(sym: Symbol): Symbol =
+ if (sym.isClass || sym.isModule || sym == NoSymbol) sym else ownerTpl(sym.owner)
+ val fixedSym = if (inTpl.sym.isModule) inTpl.sym.moduleClass else inTpl.sym
+ aType.asSeenFrom(fixedSym.thisType, ownerTpl(dclSym))
+ }
+ makeType(tpe, inTpl)
}
/** */
- def makeType(aType: Type): TypeEntity =
+ def makeType(aType: Type, inTpl: => TemplateImpl): TypeEntity =
new TypeEntity {
private val nameBuffer = new StringBuilder
private var refBuffer = new immutable.TreeMap[Int, (TemplateEntity, Int)]
@@ -446,9 +492,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
nameBuffer append sep
appendTypes0(tps, sep)
}
- private def appendType0(tpe: Type): Unit = tpe.normalize match {
+ private def checkFunctionType(tpe: TypeRef): Boolean = {
+ val TypeRef(_, sym, args) = tpe
+ (args.length > 0) && (args.length - 1 <= definitions.MaxFunctionArity) &&
+ (sym == definitions.FunctionClass(args.length - 1))
+ }
+ private def appendType0(tpe: Type): Unit = tpe match {
/* Type refs */
- case tp: TypeRef if (definitions.isFunctionType(tp)) =>
+ case tp: TypeRef if (checkFunctionType(tp)) =>
nameBuffer append '('
appendTypes0(tp.args.init, ", ")
nameBuffer append ") ⇒ "
@@ -486,11 +537,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
}
/* Polymorphic types */
case PolyType(tparams, result) if (!tparams.isEmpty) =>
- appendType0(result)
- nameBuffer append '['
- appendTypes0(tparams map (_.tpe), ", ") // TODO: actually print the polytype's symbols (not just types)
- nameBuffer append ']'
- /* Eval-by-name types */
+ throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type")
case PolyType(tparams, result) if (tparams.isEmpty) =>
nameBuffer append '⇒'
appendType0(result)
@@ -505,10 +552,15 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def templateShouldDocument(aSym: Symbol): Boolean = {
// TODO: document sourceless entities (e.g., Any, etc), based on a new Setting to be added
(aSym.isPackageClass || (aSym.sourceFile != null)) && localShouldDocument(aSym) &&
- ( aSym.owner == NoSymbol || templateShouldDocument(aSym.owner) )
+ ( aSym.owner == NoSymbol || templateShouldDocument(aSym.owner) ) && !isEmptyJavaObject(aSym)
}
- def localShouldDocument(aSym: Symbol): Boolean =
- !aSym.isPrivate && (aSym.isProtected || aSym.privateWithin == NoSymbol) && !aSym.isSynthetic
+ def isEmptyJavaObject(aSym: Symbol): Boolean = {
+ def hasMembers = aSym.info.members.exists(s => localShouldDocument(s) && (!s.isConstructor || s.owner == aSym))
+ aSym.isModule && aSym.hasFlag(Flags.JAVA) && !hasMembers
+ }
+ def localShouldDocument(aSym: Symbol): Boolean = {
+ !aSym.isPrivate && (aSym.isProtected || aSym.privateWithin == NoSymbol) && !aSym.isSynthetic
+ }
}