diff --git a/scala3doc-testcases/src/tests/hierarchy.scala b/scala3doc-testcases/src/tests/hierarchy.scala index f7d7119e354c..1798899589d5 100644 --- a/scala3doc-testcases/src/tests/hierarchy.scala +++ b/scala3doc-testcases/src/tests/hierarchy.scala @@ -5,7 +5,7 @@ package hierarchy trait A1 trait A2[T] trait A3[A, B] - +trait A4 trait B1 extends A1 trait B2 extends A1 with A2[Int] @@ -15,7 +15,7 @@ class C1[A, B, C] extends B1 with B2 with B3 trait D1 trait D2[T, R] -trait D3 +trait D3 extends A4 class E1 extends C1[Int, String, Boolean] with D1 class E2 extends C1[Int, Boolean, Any] with D2[Int, Boolean] with D3 diff --git a/scala3doc/src/dotty/dokka/model/api/api.scala b/scala3doc/src/dotty/dokka/model/api/api.scala index 483f80a50c7d..a1af1152a7e2 100644 --- a/scala3doc/src/dotty/dokka/model/api/api.scala +++ b/scala3doc/src/dotty/dokka/model/api/api.scala @@ -177,7 +177,7 @@ extension[T] (member: Member) // TODO rename parent and knownChildren def allMembers: Seq[Member] = compositeMemberExt.fold(Nil)(_.members) def parents: Seq[LinkToType] = compositeMemberExt.fold(Nil)(_.parents) - def directParents: Seq[Signature] = compositeMemberExt.fold(Nil)(_.directParents) + def directParents: Seq[LinkToType] = compositeMemberExt.fold(Nil)(_.directParents) def knownChildren: Seq[LinkToType] = compositeMemberExt.fold(Nil)(_.knownChildren) def companion: Option[DRI] = compositeMemberExt.fold(None)(_.companion) diff --git a/scala3doc/src/dotty/dokka/model/api/internalExtensions.scala b/scala3doc/src/dotty/dokka/model/api/internalExtensions.scala index de11e0cd2799..b667eb142490 100644 --- a/scala3doc/src/dotty/dokka/model/api/internalExtensions.scala +++ b/scala3doc/src/dotty/dokka/model/api/internalExtensions.scala @@ -40,7 +40,7 @@ object MemberExtension extends BaseKey[Documentable, MemberExtension]: case class CompositeMemberExtension( members : Seq[Member] = Nil, - directParents: Seq[Signature] = Nil, + directParents: Seq[LinkToType] = Nil, parents: Seq[LinkToType] = Nil, knownChildren: Seq[LinkToType] = Nil, companion: Option[DRI] = None, diff --git a/scala3doc/src/dotty/dokka/model/api/membersUtils.scala b/scala3doc/src/dotty/dokka/model/api/membersUtils.scala index 0415fb7b6854..e13048bb1c95 100644 --- a/scala3doc/src/dotty/dokka/model/api/membersUtils.scala +++ b/scala3doc/src/dotty/dokka/model/api/membersUtils.scala @@ -20,7 +20,7 @@ extension (s: Signature) extension (m: Member) def getDirectParentsAsStrings: Seq[String] = - m.directParents.map(_.getName).sorted + m.directParents.map(_.signature.getName).sorted def getParentsAsStrings: Seq[String] = m.parents.map(_.signature.getName).sorted def getKnownChildrenAsStrings: Seq[String] = diff --git a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala index e30d897d961a..c317f3e67cc1 100644 --- a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala @@ -88,16 +88,16 @@ trait ClassLikeSupport: val graph = HierarchyGraph.withEdges(getSupertypesGraph(classDef, LinkToType(selfSiangture, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)))) + val compositeExt = if signatureOnly then CompositeMemberExtension.empty else CompositeMemberExtension( classDef.extractPatchedMembers, - classDef.getParents.map(_.dokkaType.asSignature), + classDef.getParentsAsLinkToTypes, supertypes, Nil, classDef.getCompanion ) - mkMember( classDef.symbol, MemberExtension( @@ -206,7 +206,7 @@ trait ClassLikeSupport: Kind.Class(Nil, Nil) parsedClasslike.withKind( - Kind.Given(cls, givenParents, parentTpe.flatMap(extractImplicitConversion)) + Kind.Given(cls, givenParents.map(_.signature), parentTpe.flatMap(extractImplicitConversion)) ) } @@ -257,13 +257,20 @@ trait ClassLikeSupport: } - def getParents: List[Tree] = + def getTreeOfFirstParent: Option[Tree] = + c.getParentsAsTreeSymbolTuples.headOption.map(_._1) + + def getParentsAsLinkToTypes: List[LinkToType] = + c.getParentsAsTreeSymbolTuples.map { + (tree, symbol) => LinkToType(tree.dokkaType.asSignature, symbol.dri, bareClasslikeKind(symbol)) + } + + def getParentsAsTreeSymbolTuples: List[(Tree, Symbol)] = for parentTree <- c.parents if isValidPos(parentTree.pos) // We assume here that order is correct parentSymbol = if parentTree.symbol.isClassConstructor then parentTree.symbol.owner else parentTree.symbol if parentSymbol != defn.ObjectClass && parentSymbol != defn.AnyClass - yield parentTree - + yield (parentTree, parentSymbol) def getConstructors: List[Symbol] = membersToDocument.collect { case d: DefDef if d.symbol.isClassConstructor && c.constructor.symbol != d.symbol => d.symbol diff --git a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala index d12e0f53b3a5..2bfbf61d13c4 100644 --- a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala @@ -8,32 +8,32 @@ trait TypesSupport: self: TastyParser => import qctx.reflect._ - def getGivenInstance(method: DefDef): Option[Bound] = { + def getGivenInstance(method: DefDef): Option[Bound] = def extractTypeSymbol(t: Tree): Option[Symbol] = t match - case tpeTree: TypeTree => - inner(tpeTree.tpe) - case other => None + case tpeTree: TypeTree => + inner(tpeTree.tpe) + case other => None def inner(tpe: TypeRepr): Option[Symbol] = tpe match - case ThisType(tpe) => inner(tpe) - case AnnotatedType(tpe, _) => inner(tpe) - case AppliedType(tpe, _) => inner(tpe) - case tp @ TermRef(qual, typeName) => - qual match - case _: TypeRepr | _: NoPrefix => Some(tp.termSymbol) - case other => None - case tp @ TypeRef(qual, typeName) => - qual match - case _: TypeRepr | _: NoPrefix => Some(tp.typeSymbol) - case other => None + case ThisType(tpe) => inner(tpe) + case AnnotatedType(tpe, _) => inner(tpe) + case AppliedType(tpe, _) => inner(tpe) + case tp @ TermRef(qual, typeName) => + qual match + case _: TypeRepr | _: NoPrefix => Some(tp.termSymbol) + case other => None + case tp @ TypeRef(qual, typeName) => + qual match + case _: TypeRepr | _: NoPrefix => Some(tp.typeSymbol) + case other => None val typeSymbol = extractTypeSymbol(method.returnTpt) typeSymbol.map(_.tree).collect { - case c: ClassDef => c.getParents.headOption - case _ => Some(method.returnTpt) + case c: ClassDef => c.getTreeOfFirstParent + case _ => Some(method.returnTpt) }.flatten.map(_.dokkaType) - } + given TreeSyntax: AnyRef with extension (tpeTree: Tree) diff --git a/scala3doc/src/dotty/dokka/transformers/InheritanceInformationTransformer.scala b/scala3doc/src/dotty/dokka/transformers/InheritanceInformationTransformer.scala index 51a9e01e5c09..c298550608de 100644 --- a/scala3doc/src/dotty/dokka/transformers/InheritanceInformationTransformer.scala +++ b/scala3doc/src/dotty/dokka/transformers/InheritanceInformationTransformer.scala @@ -14,11 +14,15 @@ class InheritanceInformationTransformer(using context: DocContext) extends Modul override def apply(original: DModule): DModule = val subtypes = getSupertypes(original.getPackages.get(0)).groupBy(_._1).transform((k, v) => v.map(_._2)) original.updateMembers { m => - val st: Seq[LinkToType] = subtypes.getOrElse(m.dri, Nil) - val rootMemberWithBareClasslikeKind = m.asLink.copy(kind = bareClasslikeKind(m.kind)) - m.withKnownChildren(st).withNewGraphEdges(st.map(_ -> rootMemberWithBareClasslikeKind)) + val edges = getEdges(m.asLink.copy(kind = bareClasslikeKind(m.kind)), subtypes) + val st: Seq[LinkToType] = edges.map(_._1).distinct + m.withKnownChildren(st).withNewGraphEdges(edges) } + private def getEdges(ltt: LinkToType, subtypes: Map[DRI, Seq[LinkToType]]): Seq[(LinkToType, LinkToType)] = + val st: Seq[LinkToType] = subtypes.getOrElse(ltt.dri, Nil) + st.flatMap(s => Seq(s -> ltt) ++ getEdges(s, subtypes)) + private def bareClasslikeKind(kind: Kind): Kind = kind match case _: Kind.Trait => Kind.Trait(Nil, Nil) case _: Kind.Class => Kind.Class(Nil, Nil) @@ -27,5 +31,5 @@ class InheritanceInformationTransformer(using context: DocContext) extends Modul private def getSupertypes(c: Member): Seq[(DRI, LinkToType)] = val selfMapping = if !c.kind.isInstanceOf[Classlike] then Nil - else c.parents.map(_._2 -> c.asLink) + else c.directParents.map(_._2 -> c.asLink) c.allMembers.flatMap(getSupertypes) ++ selfMapping diff --git a/scala3doc/src/dotty/dokka/translators/ScalaSignatureProvider.scala b/scala3doc/src/dotty/dokka/translators/ScalaSignatureProvider.scala index ec70415ea6c5..8994b42810b8 100644 --- a/scala3doc/src/dotty/dokka/translators/ScalaSignatureProvider.scala +++ b/scala3doc/src/dotty/dokka/translators/ScalaSignatureProvider.scala @@ -79,8 +79,8 @@ object ScalaSignatureProvider: member.directParents match case Nil => builder case extendType :: withTypes => - val extendPart = builder.text(" extends ").signature(extendType) - withTypes.foldLeft(extendPart)((bdr, tpe) => bdr.text(" with ").signature(tpe)) + val extendPart = builder.text(" extends ").signature(extendType.signature) + withTypes.foldLeft(extendPart)((bdr, tpe) => bdr.text(" with ").signature(tpe.signature)) private def givenClassSignature(member: Member, cls: Kind.Class, builder: SignatureBuilder): SignatureBuilder = val prefixes = builder diff --git a/scala3doc/test/dotty/dokka/diagram/HierarchyTest.scala b/scala3doc/test/dotty/dokka/diagram/HierarchyTest.scala index 15c7723ae77a..f197bea3aa97 100644 --- a/scala3doc/test/dotty/dokka/diagram/HierarchyTest.scala +++ b/scala3doc/test/dotty/dokka/diagram/HierarchyTest.scala @@ -44,7 +44,7 @@ class HierarchyTest extends ScaladocTest("hierarchy"): ) } if (x.getName == "E2") { - assertEquals(List("A1", "A2[Int]", "A3[Int, String]", "Any", "B1", "B2", "B3", "C1[Int, Boolean, Any]", "D2[Int, Boolean]", "D3", "Matchable", "Object"), x.getParentsAsStrings) + assertEquals(List("A1", "A2[Int]", "A3[Int, String]", "A4", "Any", "B1", "B2", "B3", "C1[Int, Boolean, Any]", "D2[Int, Boolean]", "D3", "Matchable", "Object"), x.getParentsAsStrings) assertEquals(List("C1[Int, Boolean, Any]", "D2[Int, Boolean]", "D3"), x.getDirectParentsAsStrings) assertEquals(List.empty, x.getKnownChildrenAsStrings) val graph = MemberExtension.getFrom(x).map(_.graph) @@ -55,6 +55,7 @@ class HierarchyTest extends ScaladocTest("hierarchy"): "A1" -> "Object", "A2[Int]" -> "Object", "A3[Int, String]" -> "Object", + "A4" -> "Object", "B1" -> "Object", "B1" -> "A1", "B2" -> "Object", @@ -72,6 +73,7 @@ class HierarchyTest extends ScaladocTest("hierarchy"): "E2" -> "D2[Int, Boolean]", "E2" -> "D3", "D2[Int, Boolean]" -> "Object", + "D3" -> "A4", "D3" -> "Object", "E2" -> "C1[Int, Boolean, Any]" ), @@ -90,11 +92,12 @@ class HierarchyTest extends ScaladocTest("hierarchy"): "Matchable" -> "Any", "Object" -> "Any", "A2[T]" -> "Object", - "B2" -> "A2[T]", // These are not actually true, becuase we lose information about hierarchy in subtypes and their possible mapping to supertypes other that that type itself, e. g. linking to `Object` + "B2" -> "A2[T]", "B3" -> "A2[T]", - "C1[A, B, C]" -> "A2[T]", - "E1" -> "A2[T]", - "E2" -> "A2[T]" + "C1[A, B, C]" -> "B2", + "C1[A, B, C]" -> "B3", + "E1" -> "C1[A, B, C]", + "E2" -> "C1[A, B, C]" ), graph.get.edges.map((a, b) => (a.signature.getName, b.signature.getName)).toSet )