Skip to content

Scaladoc: Fix filtering extensions. Better support for exports #14125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions scaladoc-testcases/src/tests/exports.scala

This file was deleted.

45 changes: 45 additions & 0 deletions scaladoc-testcases/src/tests/exports1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package tests
package exports1

class A: //unexpected
def aDefInt: Int
= 1
def aDef1: 1
= 1
val aValInt: Int
= 1
val aVal1: 1
= 1
var aVarInt: Int
= 1
var aVar1: 1
= 1
type HKT[T[_], X] //expected: final type HKT = [T[_], X] =>> HKT[T, X]
= T[X]
type SomeRandomType = (List[_] | Seq[_]) & String //expected: final type SomeRandomType = SomeRandomType
def x[T[_], X](x: X): HKT[T, X]
= ???
def fn[T, U]: T => U
= ???
object Object //expected: val Obj: Object.type
val x: HKT[List, Int]
= ???
class Class(val a: Int, val b: Int) extends Serializable //expected: final type Class = Class
enum Enum: //expected: final type Enum = Enum
case A
case B(i: Int)
case C[T]() extends Enum

object X: //unexpected
def xDefInt: Int
= 1
def xDef1: 1
= 1
val xValInt: Int
= 1
val xVal1: 1
= 1
var xVarInt: Int
= 1
var xVar1: 1
= 1
12 changes: 12 additions & 0 deletions scaladoc-testcases/src/tests/exports2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package tests
package exports2

import exports1._

class B:
val a: A
= new A
export a.{Object => Obj, _}
export X._
def obj: Obj.type
= Obj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ class DocumentableList extends Component {
return isElementVisible;
}).length;

findRefs("span.groupHeader", listRef).forEach(h => {
const headerSiblings = this.state.list.getSectionListElementsRefs(h.parentNode).map(ref => this.state.list.toListElement(ref))
const isHeaderVisible = headerSiblings.filter(s => this.state.list.isElementVisible(s, filter)) != 0

this.toggleDisplayStyles(isHeaderVisible, h)
})

this.toggleDisplayStyles(isListVisible, listRef);

return isListVisible;
Expand Down
8 changes: 6 additions & 2 deletions scaladoc/src/dotty/tools/scaladoc/api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ enum Kind(val name: String):
case Constructor(base: Kind.Def) extends Kind("def")
case Var extends Kind("var")
case Val extends Kind("val")
case Exported(m: Kind.Def) extends Kind("export")
case Exported(base: Kind) extends Kind("export")
case Type(concreate: Boolean, opaque: Boolean, typeParams: Seq[TypeParameter])
extends Kind("type") // should we handle opaque as modifier?
case Given(kind: Def | Class | Val.type, as: Option[Signature], conversion: Option[ImplicitConversion])
Expand All @@ -76,7 +76,7 @@ enum Kind(val name: String):
enum Origin:
case ImplicitlyAddedBy(name: String, dri: DRI)
case ExtensionFrom(name: String, dri: DRI)
case ExportedFrom(name: String, dri: Option[DRI])
case ExportedFrom(link: Option[Link])
case Overrides(overriddenMembers: Seq[Overridden])
case RegularlyDefined

Expand Down Expand Up @@ -186,8 +186,12 @@ extension[T] (member: Member)
def asLink: LinkToType = LinkToType(member.signature, member.dri, member.kind)
def membersBy(op: Member => Boolean): Seq[Member] = member.members.filter(op)

def withDRI(dri: DRI): Member = member.copy(dri = dri)

def withMembers(newMembers: Seq[Member]): Member = member.copy(members = newMembers)

def withName(name: String): Member = member.copy(name = name)

def updateRecusivly(op: Member => Member): Member =
val newMembers = member.members.map(_.updateRecusivly(op))
op(member).withMembers(newMembers)
Expand Down
11 changes: 5 additions & 6 deletions scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,9 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext
Seq("Implicitly added by ", renderLink(name, dri))
case Origin.ExtensionFrom(name, dri) =>
Seq("Extension method from ", renderLink(name, dri))
case Origin.ExportedFrom(name, dri) =>
val signatureName: TagArg = dri match
case Some(dri: DRI) => renderLink(name, dri)
case None => name
case Origin.ExportedFrom(Some(link)) =>
val signatureName: TagArg = link match
case Link(name, dri) => renderLink(name, dri)
Seq("Exported from ", signatureName)
case _ => Nil
}
Expand All @@ -132,7 +131,7 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext
val depStyle = if member.deprecated.isEmpty then "" else "deprecated"
val nameClasses = cls := s"documentableName $depStyle"

val rawBuilder = ScalaSignatureProvider.rawSignature(member, InlineSignatureBuilder())
val rawBuilder = ScalaSignatureProvider.rawSignature(member, InlineSignatureBuilder())()
val inlineBuilder = rawBuilder.asInstanceOf[InlineSignatureBuilder]
val kind :: modifiersRevered = inlineBuilder.preName
val signature = inlineBuilder.names.reverse
Expand Down Expand Up @@ -287,7 +286,7 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext
.functionParameters(on.argsLists)
.asInstanceOf[InlineSignatureBuilder].names.reverse
val sig = typeSig ++ Signature(Plain(s"(${on.name}: ")) ++ on.signature ++ Signature(Plain(")")) ++ argsSig
MGroup(span(sig.map(renderElement)), members.sortBy(_.name).toSeq, on.name)
MGroup(span(cls := "groupHeader")(sig.map(renderElement)), members.sortBy(_.name).toSeq, on.name)
}.toSeq

div(cls := "membersList")(renderTabs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer:
case m: Member if m.kind != Kind.RootPackage =>
val descr = m.dri.asFileLocation
def processMember(member: Member): Seq[JSON] =
val signatureBuilder = ScalaSignatureProvider.rawSignature(member, InlineSignatureBuilder()).asInstanceOf[InlineSignatureBuilder]
val signatureBuilder = ScalaSignatureProvider.rawSignature(member, InlineSignatureBuilder())().asInstanceOf[InlineSignatureBuilder]
val sig = Signature(Plain(s"${member.kind.name} "), Plain(member.name)) ++ signatureBuilder.names.reverse
val entry = mkEntry(member.dri, member.name, flattenToText(sig), descr, member.kind.name)
val children = member
Expand Down
42 changes: 27 additions & 15 deletions scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,21 +149,23 @@ trait ClassLikeSupport:
}

case dd: DefDef if !dd.symbol.isHiddenByVisibility && dd.symbol.isExported && !dd.symbol.isArtifact =>
val exportedTarget = dd.rhs.collect {
case a: Apply => a.fun.asInstanceOf[Select]
case s: Select => s
dd.rhs.map {
case TypeApply(rhs, _) => rhs
case Apply(TypeApply(rhs, _), _) => rhs
case rhs => rhs
}.map(_.tpe.termSymbol).filter(_.exists).map(_.tree).map {
case v: ValDef if v.symbol.flags.is(Flags.Module) && !v.symbol.flags.is(Flags.Synthetic) =>
v.symbol.owner -> Symbol.newVal(c.symbol, dd.name, v.tpt.tpe, Flags.Final, Symbol.noSymbol).tree
case other => other.symbol.owner -> other
}.flatMap { (originalOwner, tree) =>
parseMember(c)(tree)
.map { m => m
.withDRI(dd.symbol.dri)
.withName(dd.symbol.normalizedName)
.withKind(Kind.Exported(m.kind))
.withOrigin(Origin.ExportedFrom(Some(Link(originalOwner.normalizedName, originalOwner.dri))))
}
}
val functionName = exportedTarget.fold("function")(_.name)
val instanceName = exportedTarget.collect {
case Select(qualifier: Select, _) => qualifier.name
case Select(qualifier: Ident, _) => qualifier.tpe.typeSymbol.normalizedName
}.getOrElse("instance")
val dri = dd.rhs.collect {
case s: Select if s.symbol.isDefDef => s.symbol.dri
}.orElse(exportedTarget.map(_.qualifier.tpe.typeSymbol.dri))

Some(parseMethod(c, dd.symbol, specificKind = Kind.Exported(_))
.withOrigin(Origin.ExportedFrom(s"$instanceName.$functionName", dri)))

case dd: DefDef if !dd.symbol.isHiddenByVisibility && !dd.symbol.isSyntheticFunc && !dd.symbol.isExtensionMethod && !dd.symbol.isArtifact =>
Some(parseMethod(c, dd.symbol))
Expand Down Expand Up @@ -423,7 +425,17 @@ trait ClassLikeSupport:
val defaultKind = Kind.Type(!isTreeAbstract(typeDef.rhs), typeDef.symbol.isOpaque, generics).asInstanceOf[Kind.Type]
val kind = if typeDef.symbol.flags.is(Flags.Enum) then Kind.EnumCase(defaultKind)
else defaultKind
mkMember(typeDef.symbol, kind, tpeTree.asSignature)(deprecated = typeDef.symbol.isDeprecated())

if typeDef.symbol.flags.is(Flags.Exported)
then {
val origin = Some(tpeTree).flatMap {
case TypeBoundsTree(l: TypeTree, h: TypeTree) if l.tpe == h.tpe =>
Some(Link(l.tpe.typeSymbol.owner.name, l.tpe.typeSymbol.owner.dri))
case _ => None
}
mkMember(typeDef.symbol, Kind.Exported(kind), tpeTree.asSignature)(deprecated = typeDef.symbol.isDeprecated(), origin = Origin.ExportedFrom(origin))
}
else mkMember(typeDef.symbol, kind, tpeTree.asSignature)(deprecated = typeDef.symbol.isDeprecated())

def parseValDef(c: ClassDef, valDef: ValDef): Member =
def defaultKind = if valDef.symbol.flags.is(Flags.Mutable) then Kind.Var else Kind.Val
Expand Down
3 changes: 2 additions & 1 deletion scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ trait TypesSupport:
private def typeBoundsTreeOfHigherKindedType(using Quotes)(low: reflect.TypeRepr, high: reflect.TypeRepr) =
import reflect._
def regularTypeBounds(low: TypeRepr, high: TypeRepr) =
typeBound(low, low = true) ++ typeBound(high, low = false)
if low == high then keyword(" = ").l ++ inner(low)
else typeBound(low, low = true) ++ typeBound(high, low = false)
high.match
case TypeLambda(params, paramBounds, resType) =>
if resType.typeSymbol == defn.AnyClass then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object FilterAttributes:
private def origin(m: Member): Map[String, String] = m.origin match
case Origin.ImplicitlyAddedBy(name, _) => Map("implicitly" -> s"by $name")
case Origin.ExtensionFrom(name, _) => Map("extension" -> s"from $name")
case Origin.ExportedFrom(name, _) => Map("export" -> s"from $name")
case Origin.ExportedFrom(Some(link)) => Map("export" -> s"from ${link.name}}")
case _ => Map.empty


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package dotty.tools.scaladoc
package translators

object ScalaSignatureProvider:
def rawSignature(documentable: Member, builder: SignatureBuilder): SignatureBuilder =
documentable.kind match
def rawSignature(documentable: Member, builder: SignatureBuilder)(kind: Kind = documentable.kind): SignatureBuilder =
kind match
case Kind.Extension(_, m) =>
extensionSignature(documentable, m, builder)
case Kind.Exported(d) =>
methodSignature(documentable, d, builder)
rawSignature(documentable, builder)(d)
case d: Kind.Def =>
methodSignature(documentable, d, builder)
case Kind.Constructor(d) =>
Expand All @@ -33,7 +33,7 @@ object ScalaSignatureProvider:
case trt: Kind.Trait =>
traitSignature(documentable, trt, builder)
case Kind.Val | Kind.Var | Kind.Implicit(Kind.Val, _) =>
fieldSignature(documentable, documentable.kind.name, builder)
fieldSignature(documentable, kind.name, builder)
case tpe: Kind.Type =>
typeSignature(tpe, documentable, builder)
case Kind.Package =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,5 @@ class SpecializedSignature extends SignatureTest("specializedSignature", Signatu
class ContextBounds extends SignatureTest("contextBounds", SignatureTest.all)

class FBoundedTypeParameters extends SignatureTest("fboundedTypeParameters", SignatureTest.all)

class Exports extends SignatureTest("exports2", SignatureTest.all, sourceFiles = List("exports1", "exports2"))