Skip to content

Scala3doc: Bugfixes related to symbol names and extension methods #10334

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 5 commits into from
Nov 23, 2020
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
2 changes: 1 addition & 1 deletion scala3doc/src/dotty/dokka/model/api/api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ enum Modifier(val name: String, val prefix: Boolean):
case Opaque extends Modifier("opaque", true)
case Open extends Modifier("open", true)

case class ExtensionTarget(name: String, signature: Signature, dri: DRI)
case class ExtensionTarget(name: String, signature: Signature, dri: DRI, position: Long)
case class ImplicitConversion(from: DRI, to: DRI)
trait ImplicitConversionProvider { def conversion: Option[ImplicitConversion] }
trait Classlike
Expand Down
28 changes: 14 additions & 14 deletions scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ trait ClassLikeSupport:
object DClass:
def apply[T >: DClass](classDef: ClassDef)(
dri: DRI = classDef.symbol.dri,
name: String = classDef.name,
name: String = classDef.symbol.normalizedName,
signatureOnly: Boolean = false,
modifiers: Seq[Modifier] = classDef.symbol.getExtraModifiers(),
): DClass =
Expand Down Expand Up @@ -109,7 +109,12 @@ trait ClassLikeSupport:
private def parseMember(s: Tree): Option[Member] = processTreeOpt(s)(s match
case dd: DefDef if !dd.symbol.isHiddenByVisibility && !dd.symbol.isSyntheticFunc && dd.symbol.isExtensionMethod =>
dd.symbol.extendedSymbol.map { extSym =>
val target = ExtensionTarget(extSym.symbol.name, extSym.tpt.dokkaType.asSignature, extSym.tpt.symbol.dri)
val target = ExtensionTarget(
extSym.symbol.normalizedName,
extSym.tpt.dokkaType.asSignature,
extSym.tpt.symbol.dri,
extSym.symbol.pos.start
)
parseMethod(dd.symbol, kind = Kind.Extension(target))
}
// TODO check given methods?
Expand Down Expand Up @@ -164,7 +169,7 @@ trait ClassLikeSupport:
private def parseInheritedMember(s: Tree): Option[Member] = processTreeOpt(s)(s match
case c: ClassDef if c.symbol.shouldDocumentClasslike && !c.symbol.isGiven => Some(parseClasslike(c, signatureOnly = true))
case other => parseMember(other)
).map(_.withOrigin(Origin.InheritedFrom(s.symbol.owner.name, s.symbol.owner.dri)))
).map(_.withOrigin(Origin.InheritedFrom(s.symbol.owner.normalizedName, s.symbol.owner.dri)))

extension (c: ClassDef):
def membersToDocument = c.body.filterNot(_.symbol.isHiddenByVisibility)
Expand Down Expand Up @@ -197,7 +202,7 @@ trait ClassLikeSupport:
}.toList

def getParameterModifier(parameter: Symbol): String =
val fieldSymbol = c.symbol.field(parameter.name)
val fieldSymbol = c.symbol.field(parameter.normalizedName)
if fieldSymbol.flags.is(Flags.Mutable) then "var "
else if fieldSymbol.flags.is(Flags.ParamAccessor) && !c.symbol.flags.is(Flags.Case) && !fieldSymbol.flags.is(Flags.Private) then "val "
else ""
Expand All @@ -221,7 +226,6 @@ trait ClassLikeSupport:

def parseObject(classDef: ClassDef, signatureOnly: Boolean = false)(using ctx: Context): DClass =
DClass(classDef)(
name = classDef.name.stripSuffix("$"),
// All objects are final so we do not need final modifer!
modifiers = classDef.symbol.getExtraModifiers().filter(_ != Modifier.Final),
signatureOnly = signatureOnly
Expand Down Expand Up @@ -266,11 +270,7 @@ trait ClassLikeSupport:
Kind.Implicit(Kind.Def, None)
else kind

val name = methodKind match
case Kind.Constructor => "this"
case Kind.Given(_, _) => methodSymbol.name.stripPrefix("given_")
case Kind.Extension(_) => methodSymbol.name.stripPrefix("extension_")
case _ => methodSymbol.name
val name = method.symbol.normalizedName

new DFunction(
methodSymbol.dri,
Expand Down Expand Up @@ -302,7 +302,7 @@ trait ClassLikeSupport:
def parseArgument(argument: ValDef, prefix: Symbol => String, isExtendedSymbol: Boolean = false, isGrouped: Boolean = false): DParameter =
new DParameter(
argument.symbol.dri,
prefix(argument.symbol) + argument.symbol.name,
prefix(argument.symbol) + argument.symbol.normalizedName,
argument.symbol.documentation.asJava,
null,
argument.tpt.dokkaType,
Expand All @@ -320,7 +320,7 @@ trait ClassLikeSupport:
else ""

new DTypeParameter(
Invariance(TypeParameter(argument.symbol.dri, variancePrefix + argument.symbol.name, null)),
Invariance(TypeParameter(argument.symbol.dri, variancePrefix + argument.symbol.normalizedName, null)),
argument.symbol.documentation.asJava,
null,
JList(argument.rhs.dokkaType),
Expand All @@ -343,7 +343,7 @@ trait ClassLikeSupport:

new DProperty(
typeDef.symbol.dri,
typeDef.name,
typeDef.symbol.normalizedName,
/*documentation =*/ typeDef.symbol.documentation.asJava,
/*expectPresentInSet =*/ null, // unused
/*sources =*/ JMap(),
Expand Down Expand Up @@ -374,7 +374,7 @@ trait ClassLikeSupport:

new DProperty(
valDef.symbol.dri,
valDef.name,
valDef.symbol.normalizedName,
/*documentation =*/ valDef.symbol.documentation.asJava,
/*expectPresentInSet =*/ null, // unused
/*sources =*/ JMap(),
Expand Down
13 changes: 13 additions & 0 deletions scala3doc/src/dotty/dokka/tasty/NameNormalizer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dotty.dokka.tasty

import dotty.dokka._

trait NameNormalizer { self: TastyParser =>
import qctx.reflect._
extension (s: Symbol) def normalizedName: String = {
val withoutGivenPrefix = if s.isGiven then s.name.stripPrefix("given_") else s.name
val withoutObjectSuffix = if s.flags.is(Flags.Object) then withoutGivenPrefix.stripSuffix("$") else withoutGivenPrefix
val constructorNormalizedName = if s.isClassConstructor then "this" else withoutObjectSuffix
constructorNormalizedName
}
}
4 changes: 2 additions & 2 deletions scala3doc/src/dotty/dokka/tasty/TastyParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ trait DokkaBaseTastyInspector:

/** Parses a single Tasty compilation unit. */
case class TastyParser(qctx: QuoteContext, inspector: DokkaBaseTastyInspector, config: DottyDokkaConfig)
extends ScaladocSupport with BasicSupport with TypesSupport with ClassLikeSupport with SyntheticsSupport with PackageSupport:
extends ScaladocSupport with BasicSupport with TypesSupport with ClassLikeSupport with SyntheticsSupport with PackageSupport with NameNormalizer:
import qctx.reflect._

def sourceSet = inspector.sourceSet
Expand All @@ -168,7 +168,7 @@ case class TastyParser(qctx: QuoteContext, inspector: DokkaBaseTastyInspector, c

private def errorMsg[T](a: Any, m: => String, e: Throwable): Option[T] =
val msg = try m catch case e: Throwable => a.toString
println(s"ERROR: tree is faling: msg")
println(s"ERROR: tree is faling: $msg")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

e.printStackTrace()
throw e

Expand Down
2 changes: 1 addition & 1 deletion scala3doc/src/dotty/dokka/tasty/TypesSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ trait TypesSupport:

private def link(symbol: Symbol)(using cxt: Context): List[JProjection] = {
val suffix = if symbol.isValDef then texts(".type") else Nil
(new TypeParameter(symbol.dri, symbol.name, null)) :: suffix
(new TypeParameter(symbol.dri, symbol.normalizedName, null)) :: suffix
}

private def commas(lists: List[List[JProjection]]) = lists match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,25 @@ import dotty.dokka.model.api._
class ImplicitMembersExtensionTransformer(ctx: DokkaContext) extends DocumentableTransformer:
override def invoke(original: DModule, context: DokkaContext): DModule =
val classlikeMap = original.driMap
val logger = context.getLogger

def retrieveCompanion(m: Member) = m match {
case classlike: DClass =>
val comp = ClasslikeExtension.getFrom(classlike).flatMap(_.companion)
comp.flatMap { dri =>
val res = classlikeMap.get(dri)
if res.isEmpty then logger.warn(s"Companion for class ${classlike.name} exists but is missing in classlike map")
res
}
case _ => None
}

def expandMember(outerMembers: Seq[Member])(c: Member): Member =
val companion = c match
case classlike: DClass => ClasslikeExtension.getFrom(classlike).flatMap(_.companion).flatMap(classlikeMap.get)
case _ => None
val companion = retrieveCompanion(c)

val allParents = c.parents.flatMap(p => classlikeMap.get(p.dri))

val parentCompanions = allParents.flatMap {
case cls: DClasslike => ClasslikeExtension.getFrom(cls).flatMap(_.companion).flatMap(classlikeMap.get)
case _ => None
}
val parentCompanions = allParents.flatMap(retrieveCompanion)

// TODO (#220): We can expand this on generic etc
val implictSources = outerMembers ++ companion.toSeq ++ parentCompanions
Expand All @@ -34,7 +41,7 @@ class ImplicitMembersExtensionTransformer(ctx: DokkaContext) extends Documentabl

val MyDri = c.getDri
def collectApplicableMembers(source: Member): Seq[Member] = source.allMembers.flatMap {
case m @ Member(_, _, _, Kind.Extension(ExtensionTarget(_, _, MyDri)), Origin.DefinedWithin) =>
case m @ Member(_, _, _, Kind.Extension(ExtensionTarget(_, _, MyDri, _)), Origin.DefinedWithin) =>
Seq(m.withOrigin(Origin.ExtensionFrom(source.name, source.dri)).withKind(Kind.Def))
case m @ Member(_, _, _, conversionProvider: ImplicitConversionProvider, Origin.DefinedWithin) =>
conversionProvider.conversion match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,14 @@ class ScalaPageContentBuilder(

def signature(d: Documentable) = addChildren(signatureProvider.signature(d).asScala.toList)

private def buildSignature(d: Documentable, s: Signature) = signatureProvider.asInstanceOf[ScalaSignatureProvider].signature(d, s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can move signature to ScalaSignatureProvider object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using contentBuilder field from ScalaSignatureProvider class which will be hard to obtain in object


def signature(d: Documentable, s: Signature) = addChild(buildSignature(d, s))

def inlineSignature(d: Documentable, s: Signature) = addChildren(
buildSignature(d, s).getChildren.asScala.toSeq
)

def defaultHeaders = List(
contentForDRIs(
dris = mainDRI,
Expand Down
12 changes: 10 additions & 2 deletions scala3doc/src/dotty/dokka/translators/ScalaPageCreator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,20 @@ class ScalaPageCreator(
case _ => withNamedTags
}

val withExtensionInformation = d.kind match {
case Kind.Extension(on) =>
val sourceSets = d.getSourceSets.asScala.toSet
withCompanion.cell(sourceSets = sourceSets)(_.text("Extension"))
.cell(sourceSets = sourceSets)(_.text(s"This function is an extension on (${on.name}: ").inlineSignature(d, on.signature).text(")"))
case _ => withCompanion
}

d match
case null => withCompanion
case null => withExtensionInformation
case m: Member =>
sourceLinks.pathTo(m).fold(withCompanion){ link =>
val sourceSets = m.getSourceSets.asScala.toSet
withCompanion.cell(sourceSets = sourceSets)(_.text("Source"))
withExtensionInformation.cell(sourceSets = sourceSets)(_.text("Source"))
.cell(sourceSets = sourceSets)(_.resolvedLink("(source)", link))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ class ScalaSignatureProvider(contentConverter: CommentsToContentConverter, logge
def driLink(text: String, dri: DRI): SignatureBuilder = ContentNodeBuilder(builder.driLink(text, dri))
}

override def signature(documentable: Documentable) =
def signature(d: Member, s: Signature) = signatureContent(d){ builder =>
val res = ContentNodeBuilder(builder).signature(s)
res.asInstanceOf[ContentNodeBuilder].builder
}

override def signature(documentable: Member) =
JList(signatureContent(documentable){ builder =>
val withAnnotations = ContentNodeBuilder(builder).annotationsBlock(documentable)
val res = ScalaSignatureProvider.rawSignature(documentable, withAnnotations)
Expand Down