Skip to content

Commit e98d9ef

Browse files
committed
Fix member lookups for inherited members
1 parent 86e9a42 commit e98d9ef

File tree

7 files changed

+72
-20
lines changed

7 files changed

+72
-20
lines changed

scaladoc-testcases/src/tests/links.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ object AnObject:
99
/**
1010
* Broken link, that should result a warning not break compilation
1111
* [[tests.links.AnObject]]
12-
1312
*/
1413
class LinksTest:
1514
def verifyIfLinksTestIsGenerated(b: Int): Int
16-
= 123
15+
= 123
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package tests
2+
package lookupInheritedMembers.pack1 {
3+
class A:
4+
def x = 1
5+
val y = 1
6+
type MyType
7+
8+
}
9+
package lookupInheritedMembers.pack2 {
10+
class B extends tests.lookupInheritedMembers.pack1.A
11+
}
12+
13+
package lookupInheritedMembers {
14+
/**
15+
* [[tests.lookupInheritedMembers.pack2.B.x]]
16+
* [[tests.lookupInheritedMembers.pack2.B.x]]
17+
* [[tests.lookupInheritedMembers.pack2.B.MyType]]
18+
*/
19+
class LookupInheritedMembers
20+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,8 @@ class SymOps[Q <: Quotes](val q: Q) extends JavadocAnchorCreator with Scaladoc2A
190190
// For some reason it contains `$$$` instrad of symbol name
191191
s"${sym.name}${sym.fullName}/${sym.signature.resultSig}/[${sym.signature.paramSigs.mkString("/")}]"
192192
)
193+
194+
def driInContextOfInheritingParent(par: Symbol)(using dctx: DocContext): DRI = sym.dri.copy(
195+
location = par.dri.location,
196+
externalLink = None
197+
)

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,12 @@ case class ScaladocTastyInspector()(using ctx: DocContext) extends DocTastyInspe
8080
def driFor(link: String): Option[DRI] =
8181
val symOps = new SymOps[q.type](q)
8282
import symOps._
83-
Try(QueryParser(link).readQuery()).toOption.flatMap(q =>
84-
MemberLookup.lookupOpt(q, None).map{ case (sym, _) => sym.dri}
83+
Try(QueryParser(link).readQuery()).toOption.flatMap(query =>
84+
MemberLookup.lookupOpt(query, None).map {
85+
case (sym, _, inheritingParent) => inheritingParent match
86+
case Some(parent) => sym.driInContextOfInheritingParent(parent)
87+
case None => sym.dri
88+
}
8589
)
8690

8791
ctx.staticSiteContext.foreach(_.memberLinkResolver = driFor)

scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using DocContext) {
8383

8484
object SymOps extends SymOps[qctx.type](qctx)
8585
export SymOps.dri
86+
export SymOps.driInContextOfInheritingParent
8687

8788
def resolveLink(queryStr: String): DocLink =
8889
if SchemeUri.matches(queryStr) then DocLink.ToURL(queryStr)
@@ -94,8 +95,11 @@ abstract class MarkupConversion[T](val repr: Repr)(using DocContext) {
9495
DocLink.UnresolvedDRI(queryStr, msg)
9596
case Right(query) =>
9697
MemberLookup.lookup(using qctx)(query, owner) match
97-
case Some((sym, targetText)) =>
98-
DocLink.ToDRI(sym.dri, targetText)
98+
case Some((sym, targetText, inheritingParent)) =>
99+
var dri = inheritingParent match
100+
case Some(parent) => sym.driInContextOfInheritingParent(parent)
101+
case None => sym.dri
102+
DocLink.ToDRI(dri, targetText)
99103
case None =>
100104
val txt = s"No DRI found for query"
101105
val msg = s"$txt: $queryStr"

scaladoc/src/dotty/tools/scaladoc/tasty/comments/MemberLookup.scala

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@ import scala.quoted._
55

66
trait MemberLookup {
77

8+
def memberLookupResult(using Quotes)(
9+
symbol: quotes.reflect.Symbol,
10+
label: String,
11+
inheritingParent: Option[quotes.reflect.Symbol] = None
12+
): (quotes.reflect.Symbol, String, Option[quotes.reflect.Symbol]) =
13+
(symbol, label, inheritingParent)
14+
815
def lookup(using Quotes, DocContext)(
916
query: Query,
1017
owner: quotes.reflect.Symbol,
11-
): Option[(quotes.reflect.Symbol, String)] = lookupOpt(query, Some(owner))
18+
): Option[(quotes.reflect.Symbol, String, Option[quotes.reflect.Symbol])] = lookupOpt(query, Some(owner))
1219

1320
def lookupOpt(using Quotes, DocContext)(
1421
query: Query,
1522
ownerOpt: Option[quotes.reflect.Symbol],
16-
): Option[(quotes.reflect.Symbol, String)] =
23+
): Option[(quotes.reflect.Symbol, String, Option[quotes.reflect.Symbol])] =
1724
try
1825
import quotes.reflect._
1926

@@ -26,7 +33,7 @@ trait MemberLookup {
2633
def nearestMembered(sym: Symbol): Symbol =
2734
if sym.isClassDef || sym.flags.is(Flags.Package) then sym else nearestMembered(sym.owner)
2835

29-
val res: Option[(Symbol, String)] = {
36+
val res: Option[(Symbol, String, Option[Symbol])] = {
3037
def toplevelLookup(querystrings: List[String]) =
3138
downwardLookup(querystrings, defn.PredefModule.moduleClass)
3239
.orElse(downwardLookup(querystrings, defn.ScalaPackage))
@@ -38,7 +45,7 @@ trait MemberLookup {
3845
val nearest = nearestMembered(owner)
3946
val nearestCls = nearestClass(owner)
4047
val nearestPkg = nearestPackage(owner)
41-
def relativeLookup(querystrings: List[String], owner: Symbol): Option[Symbol] = {
48+
def relativeLookup(querystrings: List[String], owner: Symbol): Option[(Symbol, Option[Symbol])] = {
4249
val isMeaningful =
4350
owner.exists
4451
// those are just an optimisation, they can be dropped if problems show up
@@ -56,26 +63,27 @@ trait MemberLookup {
5663

5764
query match {
5865
case Query.StrictMemberId(id) =>
59-
localLookup(id, nearest).nextOption.map(_ -> id)
66+
localLookup(id, nearest).nextOption.map(memberLookupResult(_, id))
6067
case Query.QualifiedId(Query.Qual.This, _, rest) =>
61-
downwardLookup(rest.asList, nearestCls).map(_ -> rest.join)
68+
downwardLookup(rest.asList, nearestCls).map(memberLookupResult(_, rest.join, _))
6269
case Query.QualifiedId(Query.Qual.Package, _, rest) =>
63-
downwardLookup(rest.asList, nearestPkg).map(_ -> rest.join)
70+
downwardLookup(rest.asList, nearestPkg).map(memberLookupResult(_, rest.join, _))
6471
case query =>
6572
val ql = query.asList
6673
toplevelLookup(ql)
6774
.orElse(relativeLookup(ql, nearest))
68-
.map(_ -> query.join)
75+
.map(memberLookupResult(_, query.join, _))
6976
}
7077

7178
case None =>
72-
toplevelLookup(query.asList).map(_ -> query.join)
79+
toplevelLookup(query.asList).map(memberLookupResult(_, query.join, _))
7380
}
7481
}
7582

7683
// println(s"looked up `$query` in ${owner.show}[${owner.flags.show}] as ${res.map(_.show)}")
7784

7885
res
86+
7987
catch
8088
case e: Exception =>
8189
// TODO (https://github.com/lampepfl/scala3doc/issues/238): proper reporting
@@ -169,11 +177,13 @@ trait MemberLookup {
169177
}
170178
}
171179

172-
private def downwardLookup(using Quotes)(query: List[String], owner: quotes.reflect.Symbol): Option[quotes.reflect.Symbol] = {
180+
private def downwardLookup(using Quotes)(
181+
query: List[String], owner: quotes.reflect.Symbol
182+
): Option[(quotes.reflect.Symbol, Option[quotes.reflect.Symbol])] = {
173183
import quotes.reflect._
174184
query match {
175185
case Nil => None
176-
case q :: Nil => localLookup(q, owner).nextOption
186+
case q :: Nil => localLookup(q, owner).nextOption.map((_, None))
177187
case q :: qs =>
178188
val lookedUp =
179189
localLookup(q, owner).toSeq
@@ -191,8 +201,18 @@ trait MemberLookup {
191201
else if s.flags.is(Flags.Module) then tm = Some(s)
192202
else if s.isClassDef || s.isTypeDef then tp = Some(s)
193203
}
204+
205+
def downwardLookUpForInheritedMembers(qs: List[String], owner: Symbol): Option[(Symbol, Option[Symbol])] =
206+
downwardLookup(qs, owner).orElse(owner.memberMethod(qs.head).headOption.map((_, Some(owner)))).orElse {
207+
val symbol = owner.memberType(qs.head)
208+
Option.when(symbol != dotty.tools.dotc.core.Symbols.NoSymbol)(symbol).map((_, Some(owner)))
209+
}.orElse {
210+
val symbol = owner.memberField(qs.head)
211+
Option.when(symbol != dotty.tools.dotc.core.Symbols.NoSymbol)(symbol).map((_, Some(owner)))
212+
}
213+
194214
pk.flatMap(downwardLookup(qs, _))
195-
.orElse(tp.flatMap(downwardLookup(qs, _)))
215+
.orElse(tp.flatMap(downwardLookUpForInheritedMembers(qs, _)))
196216
.orElse(tm.flatMap(downwardLookup(qs, _)))
197217
}
198218
}

scaladoc/test/dotty/tools/scaladoc/tasty/comments/MemberLookupTests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class LookupTestCases[Q <: Quotes](val q: Quotes) {
3737
cases.foreach { case (query, Sym(sym)) =>
3838
val lookupRes = MemberLookup.lookupOpt(parseQuery(query), None)
3939
assertTrue(s"Couldn't look up: $query", lookupRes.nonEmpty)
40-
val Some((lookedUp, _)) = lookupRes
40+
val Some((lookedUp, _, _)) = lookupRes
4141
assertSame(query, sym, lookedUp)
4242
}
4343
}
@@ -89,7 +89,7 @@ class LookupTestCases[Q <: Quotes](val q: Quotes) {
8989
)
9090

9191
cases.foreach { case ((Sym(owner), query), Sym(target)) =>
92-
val Some((lookedUp, _)) = MemberLookup.lookup(parseQuery(query), owner)
92+
val Some((lookedUp, _, _)) = MemberLookup.lookup(parseQuery(query), owner)
9393
assertSame(s"$owner / $query", target, lookedUp)
9494
}
9595
}

0 commit comments

Comments
 (0)