Skip to content

Commit 8471974

Browse files
committed
Handle overridden symbols in doc command in REPL
1 parent 76ca743 commit 8471974

File tree

2 files changed

+71
-11
lines changed

2 files changed

+71
-11
lines changed

compiler/src/dotty/tools/repl/ReplCompiler.scala

+24-11
Original file line numberDiff line numberDiff line change
@@ -155,30 +155,43 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler {
155155
def docOf(expr: String)(implicit state: State): Result[String] = {
156156
implicit val ctx: Context = state.run.runContext
157157

158-
def pickSymbol(symbol: Symbol): Symbol = {
159-
if (symbol.is(Module, butNot = ModuleClass)) symbol.moduleClass
160-
if (symbol.isConstructor) symbol.owner
161-
else symbol
162-
}
163-
158+
/** Extract the (possibly) documented symbol from `tree` */
164159
def extractSymbol(tree: tpd.Tree): Symbol = {
165160
tree match {
166161
case tpd.closureDef(defdef) => defdef.rhs.symbol
167162
case _ => tree.symbol
168163
}
169164
}
170165

166+
/**
167+
* Adapt `symbol` so that we get the one that holds the documentation.
168+
* Return also the symbols that `symbol` overrides`.
169+
*/
170+
def pickSymbols(symbol: Symbol): Iterator[Symbol] = {
171+
val selectedSymbol = {
172+
if (symbol.is(Module, butNot = ModuleClass)) symbol.moduleClass
173+
if (symbol.isConstructor) symbol.owner
174+
else symbol
175+
}
176+
177+
Iterator(selectedSymbol) ++ selectedSymbol.allOverriddenSymbols
178+
}
179+
171180
typeCheck(expr).map {
172181
case v @ ValDef(_, _, Block(stats, _)) if stats.nonEmpty =>
173182
val stat = stats.last.asInstanceOf[tpd.Tree]
174183
if (stat.tpe.isError) stat.tpe.show
175184
else {
176-
val symbol = pickSymbol(extractSymbol(stat))
177185
val doc =
178-
for { docCtx <- ctx.docCtx
179-
doc <- docCtx.docstrings.get(symbol) } yield doc.raw
180-
181-
doc.getOrElse(s"// No doc for ${symbol.show}")
186+
ctx.docCtx.flatMap { docCtx =>
187+
val symbols = pickSymbols(extractSymbol(stat))
188+
symbols.collectFirst {
189+
case sym if docCtx.docstrings.contains(sym) =>
190+
docCtx.docstrings(sym).raw
191+
}
192+
}
193+
194+
doc.getOrElse(s"// No doc for `${expr}`")
182195
}
183196

184197
case _ =>

compiler/test/dotty/tools/repl/DocTests.scala

+47
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,51 @@ class DocTests extends ReplTest {
142142
.fold(onErrors, assertEquals("/** doc */", _))
143143
}
144144

145+
@Test def docOfOverride =
146+
fromInitialState { implicit s =>
147+
compile("""abstract class A {
148+
|/** doc0 */ def foo(x: Int): Int = x + 1
149+
|/** doc1 */ def foo(x: String): String = x + "foo"
150+
|}""".stripMargin)
151+
}
152+
.andThen { implicit s =>
153+
compile("""object O extends A {
154+
| override def foo(x: Int): Int = x
155+
| /** overridden doc */ override def foo(x: String): String = x
156+
|}""".stripMargin)
157+
}
158+
.andThen { implicit s =>
159+
compiler.docOf("O.foo(_: Int)")
160+
.fold(onErrors, assertEquals("/** doc0 */", _))
161+
s
162+
}
163+
.andThen { implicit s =>
164+
compiler.docOf("O.foo(_: String)")
165+
.fold(onErrors, assertEquals("/** overridden doc */", _))
166+
}
167+
168+
@Test def docOfOverrideObject =
169+
fromInitialState { implicit s =>
170+
compile("""abstract class A {
171+
| abstract class Companion { /** doc0 */ def bar: Int }
172+
| /** companion */ def foo: Companion
173+
|}""".stripMargin)
174+
.andThen { implicit s =>
175+
compile("""object O extends A {
176+
| override object foo extends Companion {
177+
| override def bar: Int = 0
178+
| }
179+
|}""".stripMargin)
180+
}
181+
.andThen { implicit s =>
182+
compiler.docOf("O.foo")
183+
.fold(onErrors, assertEquals("/** companion */", _))
184+
s
185+
}
186+
.andThen { implicit s =>
187+
compiler.docOf("O.foo.bar")
188+
.fold(onErrors, assertEquals("/** doc0 */", _))
189+
}
190+
}
191+
145192
}

0 commit comments

Comments
 (0)