Skip to content

Commit eb81d67

Browse files
committed
Implement getScaladoc2Type without using tree show
Showing the tree or type does not return a reliable representation. The only way to create this correctly is be creating a custom printer that prints in the required format.
1 parent c466fa0 commit eb81d67

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

scaladoc/src/dotty/tools/scaladoc/tasty/Scaladoc2AnchorCreator.scala

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,66 @@ import scala.util.matching.Regex
77

88
object Scaladoc2AnchorCreator:
99

10-
def getScaladoc2Type(using Quotes)(t: reflect.Tree) =
11-
import reflect.*
12-
val regex = t match
13-
case d: DefDef => "def"
14-
case t: TypeDef => "type"
15-
case v: ValDef => "val|var"
16-
t.show(using Printer.TreeShortCode).split(regex, 2)(1).replace(" ","")
10+
def getScaladoc2Type(using Quotes)(sym: quotes.reflect.Symbol) = signatureAnchor(sym)
11+
12+
/** Creates the signature anchor
13+
*
14+
* - `X` for a `type X ...`
15+
* - `x:X` for a `val x: X`
16+
* - `f[U1,...](x1:T1,...)(impliciti1:U1,impliciti2:U2,...)...:R` for a `def f[U1, ...](x1: T1, ...)(implicit i1: U1, i2: U2...)...: R`
17+
*
18+
* Types are printed without their paths. No spaces are printed in the output.
19+
*/
20+
private def signatureAnchor(using Quotes)(sym: quotes.reflect.Symbol): String =
21+
import quotes.reflect.*
22+
def signatureType(tp: quotes.reflect.TypeRepr): String =
23+
tp match
24+
case mt @ MethodType(paramNames, paramTypes, res) =>
25+
val implicitPrefix = if mt.isImplicit then "implicit " else ""
26+
val closeClause = res match
27+
case _: MethodOrPoly => ")"
28+
case _ => "):"
29+
paramNames.zip(paramTypes.map(signatureType))
30+
.map((name, tpe) => s"$implicitPrefix$name:$tpe")
31+
.mkString("(", ",", closeClause) + signatureType(res)
32+
case PolyType(paramNames, paramBounds, res) =>
33+
val closeClause = res match
34+
case _: MethodOrPoly => "]"
35+
case _ => "]:"
36+
paramNames.zip(paramBounds.map(signatureType))
37+
.map((name, tpe) => s"$name$tpe")
38+
.mkString("[", ",", closeClause) + signatureType(res)
39+
case TypeLambda(paramNames, paramBounds, res) =>
40+
paramNames.zip(paramBounds.map(signatureType))
41+
.map((name, tpe) => s"$name$tpe")
42+
.mkString("[", ",", "]") + "=>" + signatureType(res)
43+
case ByNameType(tp) =>
44+
":" + signatureType(tp)
45+
case TypeBounds(low, hi) =>
46+
val lowBound = if low =:= defn.NothingClass.typeRef then "" else ">:" + signatureType(low)
47+
val hiBound = if low =:= defn.AnyClass.typeRef then "" else "<:" + signatureType(hi)
48+
lowBound + hiBound
49+
case tp: ParamRef =>
50+
tp.binder match
51+
case binder: MethodType => binder.paramNames(tp.paramNum) + ".type"
52+
case binder: PolyType => binder.paramNames(tp.paramNum)
53+
case binder: LambdaType => binder.paramNames(tp.paramNum)
54+
case AppliedType(tycon, args) =>
55+
args.map {
56+
case tp: TypeBounds => "_" + signatureType(tp)
57+
case tp => signatureType(tp)
58+
}.mkString(signatureType(tycon) + "[", ",", "]")
59+
case tp: AnnotatedType =>
60+
signatureType(tp.underlying) + "@" + tp.annotation.symbol.owner.name
61+
case tp: ThisType =>
62+
signatureType(tp.tref) + ".this"
63+
case tp: TypeRef =>
64+
tp.name
65+
case tp =>
66+
// TODO handle other cases without using show (show does not have a stable representation)
67+
tp.show(using Printer.TypeReprShortCode).replace(" ","")
68+
69+
sym match
70+
case sym if sym.isType => sym.name
71+
case sym if sym.flags.is(Flags.Method) => sym.name + signatureType(sym.info)
72+
case sym => sym.name + ":" + signatureType(sym.info)

scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class SymOpsWithLinkCache:
235235
def constructPathForScaladoc2: String =
236236
val l = escapeUrl(location.mkString("/"))
237237
val scaladoc2Anchor = if anchor.isDefined then {
238-
"#" + getScaladoc2Type(sym.tree)
238+
"#" + getScaladoc2Type(sym)
239239
} else ""
240240
docURL + l + extension + scaladoc2Anchor
241241

0 commit comments

Comments
 (0)