diff options
Diffstat (limited to 'src/compiler')
7 files changed, 148 insertions, 80 deletions
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 24cff1b475..0d0410c7e2 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -144,7 +144,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <li class="hideall out"><span>Hide All</span></li> <li class="showall in"><span>Show all</span></li> </ol> - <a href="docs.scala-lang.org/overviews/scaladoc/usage.html#members" target="_blank">Learn more about member selection</a> + <a href="http://docs.scala-lang.org/overviews/scaladoc/usage.html#members" target="_blank">Learn more about member selection</a> </div> } { diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 8eb6e358b9..57625a5e15 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -45,8 +45,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { memberSym.isOmittablePrefix || (closestPackage(memberSym) == closestPackage(templateSym)) } - private lazy val noSubclassCache = Set[Symbol](AnyClass, AnyRefClass, ObjectClass) - def makeModel: Option[Universe] = { val universe = new Universe { thisUniverse => thisFactory.universe = thisUniverse @@ -270,7 +268,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def parentTypes = if (sym.isPackage || sym == AnyClass) List() else { val tps = sym.tpe.parents map { _.asSeenFrom(sym.thisType, sym) } - makeParentTypes(RefinedType(tps, EmptyScope), inTpl) + makeParentTypes(RefinedType(tps, EmptyScope), Some(this), inTpl) } protected def linearizationFromSymbol(symbol: Symbol): List[(TemplateEntity, TypeEntity)] = { @@ -290,7 +288,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { /* Subclass cache */ private lazy val subClassesCache = ( - if (noSubclassCache(sym)) null + if (sym == AnyRefClass) null else mutable.ListBuffer[DocTemplateEntity]() ) def registerSubClass(sc: DocTemplateEntity): Unit = { @@ -796,10 +794,15 @@ 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, inTpl: => TemplateImpl): List[(TemplateEntity, TypeEntity)] = aType match { + def makeParentTypes(aType: Type, tpl: Option[DocTemplateImpl], inTpl: TemplateImpl): List[(TemplateEntity, TypeEntity)] = aType match { case RefinedType(parents, defs) => - val ignoreParents = Set[Symbol](AnyClass, ObjectClass) - val filtParents = parents filterNot (x => ignoreParents(x.typeSymbol)) + val ignoreParents = Set[Symbol](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)) + parents + else + parents.filterNot((p: Type) => ignoreParents(p.typeSymbol)) filtParents.map(parent => { val templateEntity = makeTemplate(parent.typeSymbol) val typeEntity = makeType(parent, inTpl) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index e7f4a9c79b..8cbf2ac1b6 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -91,7 +91,7 @@ trait ModelFactoryImplicitSupport { * default Scala imports (Predef._ for example) and the companion object of the current class, if one exists. In the * future we might want to extend this to more complex scopes. */ - def makeImplicitConversions(sym: Symbol, inTpl: => DocTemplateImpl): List[ImplicitConversionImpl] = + def makeImplicitConversions(sym: Symbol, inTpl: DocTemplateImpl): List[ImplicitConversionImpl] = // Nothing and Null are somewhat special -- they can be transformed by any implicit conversion available in scope. // But we don't want that, so we'll simply refuse to find implicit conversions on for Nothing and Null if (!(sym.isClass || sym.isTrait || sym == AnyRefClass) || sym == NothingClass || sym == NullClass) Nil @@ -148,7 +148,7 @@ trait ModelFactoryImplicitSupport { * - we also need to transform implicit parameters in the view's signature into constraints, such that Numeric[T4] * appears as a constraint */ - def makeImplicitConversion(sym: Symbol, result: SearchResult, constrs: List[TypeConstraint], context: Context, inTpl: => DocTemplateImpl): List[ImplicitConversionImpl] = + def makeImplicitConversion(sym: Symbol, result: SearchResult, constrs: List[TypeConstraint], context: Context, inTpl: DocTemplateImpl): List[ImplicitConversionImpl] = if (result.tree == EmptyTree) Nil else { // `result` will contain the type of the view (= implicit conversion method) @@ -206,7 +206,7 @@ trait ModelFactoryImplicitSupport { } } - def makeImplicitConstraints(types: List[Type], sym: Symbol, context: Context, inTpl: => DocTemplateImpl): List[Constraint] = + def makeImplicitConstraints(types: List[Type], sym: Symbol, context: Context, inTpl: DocTemplateImpl): List[Constraint] = types.flatMap((tpe:Type) => { // TODO: Before creating constraints, map typeVarToOriginOrWildcard on the implicitTypes val implType = typeVarToOriginOrWildcard(tpe) @@ -282,7 +282,7 @@ trait ModelFactoryImplicitSupport { } }) - def makeSubstitutionConstraints(subst: TreeTypeSubstituter, inTpl: => DocTemplateImpl): List[Constraint] = + def makeSubstitutionConstraints(subst: TreeTypeSubstituter, inTpl: DocTemplateImpl): List[Constraint] = (subst.from zip subst.to) map { case (from, to) => new EqualTypeParamConstraint { @@ -292,7 +292,7 @@ trait ModelFactoryImplicitSupport { } } - def makeBoundedConstraints(tparams: List[Symbol], constrs: List[TypeConstraint], inTpl: => DocTemplateImpl): List[Constraint] = + def makeBoundedConstraints(tparams: List[Symbol], constrs: List[TypeConstraint], inTpl: DocTemplateImpl): List[Constraint] = (tparams zip constrs) flatMap { case (tparam, constr) => { uniteConstraints(constr) match { @@ -341,7 +341,7 @@ trait ModelFactoryImplicitSupport { val convSym: Symbol, val toType: Type, val constrs: List[Constraint], - inTpl: => DocTemplateImpl) + inTpl: DocTemplateImpl) extends ImplicitConversion { def source: DocTemplateEntity = inTpl @@ -365,7 +365,7 @@ trait ModelFactoryImplicitSupport { case _ => error("Scaladoc implicits: Could not create template for: " + toType + " of type " + toType.getClass); None } - def targetTypeComponents: List[(TemplateEntity, TypeEntity)] = makeParentTypes(toType, inTpl) + def targetTypeComponents: List[(TemplateEntity, TypeEntity)] = makeParentTypes(toType, None, inTpl) def convertorMethod: Either[MemberEntity, String] = { var convertor: MemberEntity = null 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 a46be37d60..2099315cc6 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -30,12 +30,12 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => protected val commentCache = mutable.HashMap.empty[(global.Symbol, TemplateImpl), Comment] - def addCommentBody(sym: global.Symbol, inTpl: => TemplateImpl, docStr: String, docPos: global.Position): global.Symbol = { + def addCommentBody(sym: global.Symbol, inTpl: TemplateImpl, docStr: String, docPos: global.Position): global.Symbol = { commentCache += (sym, inTpl) -> parse(docStr, docStr, docPos) sym } - def comment(sym: global.Symbol, inTpl: => DocTemplateImpl): Option[Comment] = { + def comment(sym: global.Symbol, inTpl: DocTemplateImpl): Option[Comment] = { val key = (sym, inTpl) if (commentCache isDefinedAt key) Some(commentCache(key)) @@ -50,7 +50,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => * cases we have to give some `inTpl` comments (parent class for example) * to the comment of the symbol. * This function manages some of those cases : Param accessor and Primary constructor */ - def defineComment(sym: global.Symbol, inTpl: => DocTemplateImpl):Option[Comment] = { + def defineComment(sym: global.Symbol, inTpl: DocTemplateImpl):Option[Comment] = { //param accessor case // We just need the @param argument, we put it into the body 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 28a8c7d37d..d80999e149 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/Diagram.scala @@ -109,7 +109,7 @@ case class NormalNode(tpe: TypeEntity, tpl: Option[TemplateEntity]) extends Node case class ImplicitNode(tpe: TypeEntity, tpl: Option[TemplateEntity]) extends Node { override def isImplicitNode = true } /** An outside node is shown in packages when a class from a different package makes it to the package diagram due to - * its relation to a class in the package (and @contentDiagram showInheritedNodes annotation) */ + * its relation to a class in the template (see @contentDiagram hideInheritedNodes annotation) */ case class OutsideNode(tpe: TypeEntity, tpl: Option[TemplateEntity]) extends Node { override def isOutsideNode = true } diff --git a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala index beaa045df4..49cfaffc2e 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala @@ -19,6 +19,8 @@ import html.page.diagram.DiagramStats trait DiagramDirectiveParser { this: ModelFactory with DiagramFactory with CommentFactory with TreeFactory => + import this.global.definitions.AnyRefClass + ///// DIAGRAM FILTERS ////////////////////////////////////////////////////////////////////////////////////////////// /** @@ -48,16 +50,22 @@ trait DiagramDirectiveParser { /** Hide subclasses (for type hierarchy diagrams) */ def hideSubclasses: Boolean /** Show related classes from other objects/traits/packages (for content diagrams) */ - def showInheritedNodes: Boolean + def hideInheritedNodes: Boolean /** Hide a node from the diagram */ - def hideNode(clazz: TemplateEntity): Boolean + def hideNode(clazz: Node): Boolean /** Hide an edge from the diagram */ - def hideEdge(clazz1: TemplateEntity, clazz2: TemplateEntity): Boolean + def hideEdge(clazz1: Node, clazz2: Node): Boolean } /** Main entry point into this trait: generate the filter for inheritance diagrams */ def makeInheritanceDiagramFilter(template: DocTemplateImpl): DiagramFilter = { - val defaultFilter = if (template.isClass || template.isTrait) FullDiagram else NoDiagramAtAll + + val defaultFilter = + if (template.isClass || template.isTrait || template.sym == AnyRefClass) + FullDiagram + else + NoDiagramAtAll + if (template.comment.isDefined) makeDiagramFilter(template, template.comment.get.inheritDiagram, defaultFilter, true) else @@ -83,9 +91,9 @@ trait DiagramDirectiveParser { val hideOutgoingImplicits: Boolean = false val hideSuperclasses: Boolean = false val hideSubclasses: Boolean = false - val showInheritedNodes: Boolean = false - def hideNode(clazz: TemplateEntity): Boolean = false - def hideEdge(clazz1: TemplateEntity, clazz2: TemplateEntity): Boolean = false + val hideInheritedNodes: Boolean = false + def hideNode(clazz: Node): Boolean = false + def hideEdge(clazz1: Node, clazz2: Node): Boolean = false } /** Hide the diagram completely, no need for special filtering */ @@ -95,9 +103,9 @@ trait DiagramDirectiveParser { val hideOutgoingImplicits: Boolean = true val hideSuperclasses: Boolean = true val hideSubclasses: Boolean = true - val showInheritedNodes: Boolean = false - def hideNode(clazz: TemplateEntity): Boolean = true - def hideEdge(clazz1: TemplateEntity, clazz2: TemplateEntity): Boolean = true + val hideInheritedNodes: Boolean = true + def hideNode(clazz: Node): Boolean = true + def hideEdge(clazz1: Node, clazz2: Node): Boolean = true } /** The AnnotationDiagramFilter trait directs the diagram engine according to an annotation @@ -107,12 +115,18 @@ trait DiagramDirectiveParser { hideOutgoingImplicits: Boolean, hideSuperclasses: Boolean, hideSubclasses: Boolean, - showInheritedNodes: Boolean, + hideInheritedNodes: Boolean, hideNodesFilter: List[Pattern], hideEdgesFilter: List[(Pattern, Pattern)]) extends DiagramFilter { - def hideNode(clazz: TemplateEntity): Boolean = { - val qualifiedName = clazz.qualifiedName + private[this] def getName(n: Node): String = + if (n.tpl.isDefined) + n.tpl.get.qualifiedName + else + n.name + + def hideNode(clazz: Node): Boolean = { + val qualifiedName = getName(clazz) for (hideFilter <- hideNodesFilter) if (hideFilter.matcher(qualifiedName).matches) { // println(hideFilter + ".matcher(" + qualifiedName + ").matches = " + hideFilter.matcher(qualifiedName).matches) @@ -121,9 +135,9 @@ trait DiagramDirectiveParser { false } - def hideEdge(clazz1: TemplateEntity, clazz2: TemplateEntity): Boolean = { - val clazz1Name = clazz1.qualifiedName - val clazz2Name = clazz2.qualifiedName + def hideEdge(clazz1: Node, clazz2: Node): Boolean = { + val clazz1Name = getName(clazz1) + val clazz2Name = getName(clazz2) for ((clazz1Filter, clazz2Filter) <- hideEdgesFilter) { if (clazz1Filter.matcher(clazz1Name).matches && clazz2Filter.matcher(clazz2Name).matches) { @@ -162,7 +176,7 @@ trait DiagramDirectiveParser { var hideOutgoingImplicits0: Boolean = false var hideSuperclasses0: Boolean = false var hideSubclasses0: Boolean = false - var showInheritedNodes0: Boolean = false + var hideInheritedNodes0: Boolean = false var hideNodesFilter0: List[Pattern] = Nil var hideEdgesFilter0: List[(Pattern, Pattern)] = Nil @@ -190,8 +204,8 @@ trait DiagramDirectiveParser { hideSuperclasses0 = true case "hideSubclasses" if isInheritanceDiagram => hideSubclasses0 = true - case "showInheritedNodes" if !isInheritanceDiagram => - showInheritedNodes0 = true + case "hideInheritedNodes" if !isInheritanceDiagram => + hideInheritedNodes0 = true case HideNodesRegex(last) => val matcher = NodeSpecPattern.matcher(entry) while (matcher.find()) { @@ -225,7 +239,7 @@ trait DiagramDirectiveParser { (hideOutgoingImplicits0 == false) && (hideSuperclasses0 == false) && (hideSubclasses0 == false) && - (showInheritedNodes0 == false) && + (hideInheritedNodes0 == false) && (hideDiagram0 == false)) FullDiagram else @@ -235,7 +249,7 @@ trait DiagramDirectiveParser { hideOutgoingImplicits = hideOutgoingImplicits0, hideSuperclasses = hideSuperclasses0, hideSubclasses = hideSubclasses0, - showInheritedNodes = showInheritedNodes0, + hideInheritedNodes = hideInheritedNodes0, hideNodesFilter = hideNodesFilter0, hideEdgesFilter = hideEdgesFilter0) 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 4ae5e7a5cb..3f054b969b 100644 --- a/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala @@ -9,6 +9,8 @@ import collection.mutable // statistics import html.page.diagram.DiagramStats +import scala.collection.immutable.SortedMap + /** * This trait takes care of generating the diagram for classes and packages * @@ -18,6 +20,20 @@ import html.page.diagram.DiagramStats trait DiagramFactory extends DiagramDirectiveParser { this: ModelFactory with DiagramFactory with CommentFactory with TreeFactory => + import this.global.definitions._ + import this.global._ + + // the following can used for hardcoding different relations into the diagram, for bootstrapping purposes + lazy val AnyNode = normalNode(AnyClass) + lazy val AnyRefNode = normalNode(AnyRefClass) + lazy val AnyValNode = normalNode(AnyValClass) + lazy val NullNode = normalNode(NullClass) + lazy val NothingNode = normalNode(NothingClass) + 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) + /** Create the inheritance diagram for this template */ def makeInheritanceDiagram(tpl: DocTemplateImpl): Option[Diagram] = { @@ -35,28 +51,36 @@ trait DiagramFactory extends DiagramDirectiveParser { val thisNode = ThisNode(tpl.ownType, Some(tpl)) // superclasses - var superclasses = List[Node]() - tpl.parentTypes.collect { case p: (TemplateEntity, TypeEntity) if !classExcluded(p._1) => p } foreach { - t: (TemplateEntity, TypeEntity) => - val n = NormalNode(t._2, Some(t._1)) - superclasses ::= n - } - val filteredSuperclasses = if (diagramFilter.hideSuperclasses) Nil else superclasses + var superclasses: List[Node] = + tpl.parentTypes.collect { + case p: (TemplateEntity, TypeEntity) if !classExcluded(p._1) => NormalNode(p._2, Some(p._1)) + }.reverse // incoming implcit conversions lazy val incomingImplicitNodes = tpl.incomingImplicitlyConvertedClasses.map(tpl => ImplicitNode(tpl.ownType, Some(tpl))) - val filteredIncomingImplicits = if (diagramFilter.hideIncomingImplicits) Nil else incomingImplicitNodes // subclasses - val subclasses = tpl.directSubClasses.flatMap { - case d: TemplateEntity if !classExcluded(d) => List(NormalNode(d.ownType, Some(d))) - case _ => Nil - } - val filteredSubclasses = if (diagramFilter.hideSubclasses) Nil else subclasses + var subclasses: List[Node] = + tpl.directSubClasses.flatMap { + case d: TemplateEntity if !classExcluded(d) => List(NormalNode(d.ownType, Some(d))) + case _ => Nil + }.sortBy(_.tpl.get.name)(implicitly[Ordering[String]].reverse) // outgoing implicit coversions - lazy val implicitNodes = tpl.outgoingImplicitlyConvertedClasses.map(pair => ImplicitNode(pair._2, Some(pair._1))) - val filteredImplicitOutgoingNodes = if (diagramFilter.hideOutgoingImplicits) Nil else implicitNodes + lazy val outgoingImplicitNodes = tpl.outgoingImplicitlyConvertedClasses.map(pair => ImplicitNode(pair._2, Some(pair._1))) + + // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to change the diagrams. + // Currently, it's possible to leave nodes and edges out, but there's no way to create new nodes and edges + // The implementation would need to add the annotations and the logic to select nodes (or create new ones) + // and add edges to the diagram -- I bet it wouldn't take too long for someone to do it (one or two days + // at most) and it would be a great add to the diagrams. + if (tpl.sym == AnyRefClass) + subclasses = List(aggregationNode("All user-defined classes and traits")) + + val filteredSuperclasses = if (diagramFilter.hideSuperclasses) Nil else superclasses + val filteredIncomingImplicits = if (diagramFilter.hideIncomingImplicits) Nil else incomingImplicitNodes + val filteredSubclasses = if (diagramFilter.hideSubclasses) Nil else subclasses + val filteredImplicitOutgoingNodes = if (diagramFilter.hideOutgoingImplicits) Nil else outgoingImplicitNodes // final diagram filter filterDiagram(ClassDiagram(thisNode, filteredSuperclasses.reverse, filteredSubclasses.reverse, filteredIncomingImplicits, filteredImplicitOutgoingNodes), diagramFilter) @@ -82,39 +106,68 @@ trait DiagramFactory extends DiagramDirectiveParser { if (diagramFilter == NoDiagramAtAll) None else { - var mapNodes = Map[DocTemplateEntity, Node]() - var nodesShown = Set[DocTemplateEntity]() - var edgesAll = List[(DocTemplateEntity, List[DocTemplateEntity])]() + var mapNodes = Map[TemplateEntity, Node]() + var nodesShown = Set[TemplateEntity]() + var edgesAll = List[(TemplateEntity, List[TemplateEntity])]() // classes is the entire set of classes and traits in the package, they are the superset of nodes in the diagram // we collect classes, traits and objects without a companion, which are usually used as values(e.g. scala.None) - val dnodes = pack.members collect { - case d: DocTemplateEntity if d.isClass || d.isTrait || (d.isObject && !d.companion.isDefined) && - ((d.inTemplate == pack) || diagramFilter.showInheritedNodes) => d + val nodesAll = pack.members collect { + case d: TemplateEntity if ((!diagramFilter.hideInheritedNodes) || (d.inTemplate == pack)) => d } // for each node, add its subclasses - for (node <- dnodes if !classExcluded(node)) { - val superClasses = node.parentTypes.collect { - case (tpl: DocTemplateEntity, tpe) if tpl.inTemplate == pack && !classExcluded(tpl) => tpl - case (tpl: DocTemplateEntity, tpe) if tpl.inTemplate != pack && !classExcluded(tpl) && diagramFilter.showInheritedNodes && (pack.members contains tpl) => tpl - } - - if (!superClasses.isEmpty) { - nodesShown += node - nodesShown ++= superClasses + for (node <- nodesAll if !classExcluded(node)) { + node match { + case dnode: DocTemplateImpl => + var superClasses = dnode.parentTypes.map(_._1) + + superClasses = superClasses.filter(nodesAll.contains(_)) + + // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to change the diagrams. + if (pack.sym == ScalaPackage) + if (dnode.sym == NullClass) + superClasses = List(makeTemplate(AnyRefClass)) + else if (dnode.sym == NothingClass) + superClasses = (List(NullClass) ::: ScalaValueClasses).map(makeTemplate(_)) + + if (!superClasses.isEmpty) { + nodesShown += dnode + nodesShown ++= superClasses + } + edgesAll ::= dnode -> superClasses + case _ => } - edgesAll ::= node -> superClasses mapNodes += node -> (if (node.inTemplate == pack) NormalNode(node.ownType, Some(node)) else OutsideNode(node.ownType, Some(node))) } if (nodesShown.isEmpty) None else { - val nodes = dnodes.filter(nodesShown.contains(_)).map(mapNodes(_)) + val nodes = nodesAll.filter(nodesShown.contains(_)).map(mapNodes(_)) val edges = edgesAll.map(pair => (mapNodes(pair._1), pair._2.map(mapNodes(_)))).filterNot(pair => pair._2.isEmpty) - filterDiagram(PackageDiagram(nodes, edges), diagramFilter) + val diagram = + // TODO: Everyone should be able to use the @{inherit,content}Diagram annotation to change the diagrams. + if (pack.sym == ScalaPackage) { + // Tried it, but it doesn't look good: + // var anyRefSubtypes: List[Node] = List(mapNodes(makeTemplate(AnyRefClass))) + // var dirty = true + // do { + // val length = anyRefSubtypes.length + // anyRefSubtypes :::= edges.collect { case p: (Node, List[Node]) if p._2.exists(anyRefSubtypes.contains(_)) => p._1 } + // anyRefSubtypes = anyRefSubtypes.distinct + // dirty = (anyRefSubtypes.length != length) + // } while (dirty) + // println(anyRefSubtypes) + val anyRefSubtypes = Nil + val allAnyRefTypes = aggregationNode("All AnyRef subtypes") + val nullTemplate = makeTemplate(NullClass) + PackageDiagram(allAnyRefTypes::nodes, (mapNodes(nullTemplate), allAnyRefTypes::anyRefSubtypes)::edges.filterNot(_._1.tpl == Some(nullTemplate))) + } else + PackageDiagram(nodes, edges) + + filterDiagram(diagram, diagramFilter) } } @@ -137,18 +190,16 @@ trait DiagramFactory extends DiagramDirectiveParser { else { // Final diagram, with the filtered nodes and edges diagram match { - case ClassDiagram(thisNode, _, _, _, _) if diagramFilter.hideNode(thisNode.tpl.get) => + case ClassDiagram(thisNode, _, _, _, _) if diagramFilter.hideNode(thisNode) => None case ClassDiagram(thisNode, superClasses, subClasses, incomingImplicits, outgoingImplicits) => def hideIncoming(node: Node): Boolean = - if (node.tpl.isDefined) diagramFilter.hideNode(node.tpl.get) || diagramFilter.hideEdge(node.tpl.get, thisNode.tpl.get) - else false // hopefully we won't need to fallback here + diagramFilter.hideNode(node) || diagramFilter.hideEdge(node, thisNode) def hideOutgoing(node: Node): Boolean = - if (node.tpl.isDefined) diagramFilter.hideNode(node.tpl.get) || diagramFilter.hideEdge(thisNode.tpl.get, node.tpl.get) - else false // hopefully we won't need to fallback here + diagramFilter.hideNode(node) || diagramFilter.hideEdge(thisNode, node) // println(thisNode) // println(superClasses.map(cl => "super: " + cl + " " + hideOutgoing(cl)).mkString("\n")) @@ -166,8 +217,8 @@ trait DiagramFactory extends DiagramDirectiveParser { // (3) are destinations of hidden classes val edges: List[(Node, List[Node])] = diagram.edges.flatMap({ - case (source@Node(_, Some(tpl1)), dests) if !diagramFilter.hideNode(tpl1) => - val dests2 = dests.collect({ case node@Node(_, Some(tpl2)) if (!(diagramFilter.hideEdge(tpl1, tpl2) || diagramFilter.hideNode(tpl2))) => node }) + case (source, dests) if !diagramFilter.hideNode(source) => + val dests2 = dests.collect({ case dest if (!(diagramFilter.hideEdge(source, dest) || diagramFilter.hideNode(dest))) => dest }) if (dests2 != Nil) List((source, dests2)) else |