Skip to content

Commit 2c7c92d

Browse files
committed
Further implementation of snippet compiler. Add package name and self type to pass context
1 parent 825f6c3 commit 2c7c92d

File tree

7 files changed

+88
-22
lines changed

7 files changed

+88
-22
lines changed

scaladoc/src/dotty/tools/scaladoc/api.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,5 @@ extension (s: Signature)
233233
}.mkString
234234

235235
case class TastyMemberSource(val path: java.nio.file.Path, val lineNumber: Int)
236+
237+
case class SnippetCompilerData(val packageName: String, val classType: Option[String], val classGenerics: Option[String], val imports: List[String])

scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,17 @@ import dotty.tools.scaladoc.tasty.comments.wiki.WikiDocElement
88
import dotty.tools.scaladoc.tasty.comments.markdown.DocFlexmarkRenderer
99
import dotty.tools.scaladoc.snippets._
1010

11-
class DocRender(signatureRenderer: SignatureRenderer)(using DocContext):
12-
13-
private val snippetChecker = SnippetChecker()
11+
class DocRender(signatureRenderer: SignatureRenderer, snippetChecker: SnippetChecker)(using DocContext):
1412

1513
private val snippetCheckingFunc: Member => String => Unit =
1614
(m: Member) => {
1715
(str: String) => {
18-
snippetChecker.checkSnippet(str) match {
19-
case r @ SnippetCompilationResult(None, _) =>
20-
println(s"In member ${m.name}:")
21-
println(r.getSummary)
22-
case _ =>
23-
}
16+
snippetChecker.checkSnippet(str, m.docs.map(_.snippetCompilerData)) match {
17+
case r @ SnippetCompilationResult(None, _) =>
18+
println(s"In member ${m.name}:")
19+
println(r.getSummary)
20+
case _ =>
21+
}
2422
}
2523
}
2624

scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import java.nio.file.Files
1414
import java.nio.file.FileVisitOption
1515
import java.io.File
1616

17+
import dotty.tools.scaladoc.snippets._
18+
1719
case class Page(link: Link, content: Member | ResolvedTemplate | String, children: Seq[Page]):
1820
def withNewChildren(newChildren: Seq[Page]) = copy(children = children ++ newChildren)
1921

@@ -26,6 +28,7 @@ case class Page(link: Link, content: Member | ResolvedTemplate | String, childre
2628
class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx: DocContext)
2729
extends SiteRenderer, Resources, Locations, Writer:
2830
private val args = summon[DocContext].args
31+
private val snippetChecker = SnippetChecker()
2932
val staticSite = summon[DocContext].staticSiteContext
3033

3134
val effectiveMembers = members
@@ -75,7 +78,7 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx
7578
def link(dri: DRI): Option[String] =
7679
Some(pathToPage(currentDri, dri)).filter(_ != UnresolvedLocationLink)
7780

78-
MemberRenderer(signatureRenderer).fullMember(m)
81+
MemberRenderer(signatureRenderer, snippetChecker).fullMember(m)
7982
case t: ResolvedTemplate => siteContent(page.link.dri, t)
8083
case a: String => raw(a)
8184

@@ -122,6 +125,7 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx
122125
def render(): Unit =
123126
val renderedResources = renderResources()
124127
val sites = allPages.map(renderPage(_, Vector.empty))
128+
println(snippetChecker.summary)
125129

126130
def mkHead(page: Page): AppliedTag =
127131
val resources = page.content match

scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import dotty.tools.scaladoc.tasty.comments.markdown.DocFlexmarkRenderer
99
import com.vladsch.flexmark.util.ast.{Node => MdNode}
1010
import dotty.tools.scaladoc.tasty.comments.wiki.WikiDocElement
1111
import translators._
12+
import dotty.tools.scaladoc.snippets._
1213

13-
class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) extends DocRender(signatureRenderer):
14+
class MemberRenderer(signatureRenderer: SignatureRenderer, snippetChecker: SnippetChecker)(using DocContext) extends DocRender(signatureRenderer, snippetChecker):
1415
import signatureRenderer._
1516

1617
def doc(m: Member): Seq[AppliedTag] = m.docs.fold(Nil)(d => Seq(renderDocPart(d.body)(using m)))

scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,25 @@ class SnippetChecker(
77
private val compiler: SnippetCompiler = SnippetCompiler(),
88
private val wrapper: SnippetWrapper = SnippetWrapper()
99
):
10-
def checkSnippet(snippet: String): SnippetCompilationResult = {
11-
val wrapped = wrapper.wrap(snippet)
12-
compiler.compile(wrapped)
13-
}
10+
var warningsCount = 0
11+
var errorsCount = 0
12+
13+
def checkSnippet(snippet: String, data: Option[SnippetCompilerData]): SnippetCompilationResult = {
14+
val wrapped = wrapper.wrap(
15+
snippet,
16+
data.map(_.packageName),
17+
data.flatMap(_.classType),
18+
data.flatMap(_.classGenerics),
19+
data.map(_.imports).getOrElse(Nil)
20+
)
21+
val res = compiler.compile(wrapped)
22+
if !res.messages.filter(_.level == MessageLevel.Error).isEmpty then errorsCount = errorsCount + 1
23+
if !res.messages.filter(_.level == MessageLevel.Warning).isEmpty then warningsCount = warningsCount + 1
24+
res
25+
}
26+
27+
def summary: String = s"""
28+
|Snippet compiler summary:
29+
| Found $warningsCount warnings
30+
| Found $errorsCount errors
31+
|""".stripMargin

scaladoc/src/dotty/tools/scaladoc/snippets/SnippetWrapper.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import java.io.ByteArrayOutputStream
55
import java.io.PrintStream
66

77
class SnippetWrapper:
8-
extension (ps: PrintStream) def printlnWithIndent(indent: Int, str: String) =
8+
extension (ps: PrintStream) private def printlnWithIndent(indent: Int, str: String) =
99
ps.println((" " * indent) + str)
1010
def wrap(str: String): String =
1111
val baos = new ByteArrayOutputStream()
@@ -16,6 +16,16 @@ class SnippetWrapper:
1616
ps.println("}")
1717
baos.toString
1818

19+
def wrap(str:String, packageName: Option[String], className: Option[String], classGenerics: Option[String], imports: List[String]) =
20+
val baos = new ByteArrayOutputStream()
21+
val ps = new PrintStream(baos)
22+
ps.println(s"package ${packageName.getOrElse("snippets")}")
23+
imports.foreach(i => ps.println(s"import $i"))
24+
ps.println(s"trait Snippet${classGenerics.getOrElse("")} { ${className.fold("")(cn => s"self: $cn =>")}")
25+
str.split('\n').foreach(ps.printlnWithIndent(2, _))
26+
ps.println("}")
27+
baos.toString
28+
1929
object SnippetWrapper:
20-
val lineOffset = 2
21-
val columnOffset = 2
30+
private val lineOffset = 2
31+
private val columnOffset = 2

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

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ case class Comment (
4040
groupNames: SortedMap[String, DocPart],
4141
groupPrio: SortedMap[String, Int],
4242
/** List of conversions to hide - containing e.g: `scala.Predef.FloatArrayOps` */
43-
hideImplicitConversions: List[DocPart]
43+
hideImplicitConversions: List[DocPart],
44+
snippetCompilerData: SnippetCompilerData
4445
)
4546

4647
case class PreparsedComment(
@@ -84,8 +85,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using DocContext) {
8485
private given qctx.type = qctx
8586

8687
object SymOpsWithLinkCache extends SymOpsWithLinkCache
87-
export SymOpsWithLinkCache.dri
88-
export SymOpsWithLinkCache.driInContextOfInheritingParent
88+
export SymOpsWithLinkCache._
8989

9090
def resolveLink(queryStr: String): DocLink =
9191
if SchemeUri.matches(queryStr) then DocLink.ToURL(queryStr)
@@ -122,6 +122,38 @@ abstract class MarkupConversion[T](val repr: Repr)(using DocContext) {
122122
case _ => None
123123
}
124124

125+
private def getSnippetCompilerData(sym: qctx.reflect.Symbol): SnippetCompilerData =
126+
val packageName = sym.packageName
127+
if !sym.isPackageDef then sym.tree match {
128+
case c: qctx.reflect.ClassDef =>
129+
import qctx.reflect._
130+
import dotty.tools.dotc
131+
given dotc.core.Contexts.Context = qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
132+
val cSym = c.symbol.asInstanceOf[dotc.core.Symbols.ClassSymbol]
133+
134+
def createTypeConstructor(tpe: dotc.core.Types.Type, topLevel: Boolean = true): String = tpe match {
135+
case t @ dotc.core.Types.TypeBounds(upper, lower) => lower match {
136+
case l: dotc.core.Types.HKTypeLambda =>
137+
(if topLevel then "" else "?") + l.paramInfos.map(p => createTypeConstructor(p, false)).mkString("[",", ","]")
138+
case _ => (if topLevel then "" else "_")
139+
}
140+
}
141+
val classType =
142+
val ct = cSym.classInfo.selfType.show.replace(".this.",".")
143+
Some(ct)
144+
val classGenerics = Option.when(
145+
!cSym.typeParams.isEmpty
146+
)(
147+
cSym.typeParams.map(_.typeRef).map(t =>
148+
t.show +
149+
createTypeConstructor(t.asInstanceOf[dotc.core.Types.TypeRef].underlying)
150+
).mkString("[",", ","]")
151+
)
152+
SnippetCompilerData(packageName, classType, classGenerics, Nil)
153+
case _ => getSnippetCompilerData(sym.maybeOwner)
154+
} else SnippetCompilerData(packageName, None, None, Nil)
155+
156+
125157
final def parse(preparsed: PreparsedComment): Comment =
126158
val body = markupToDokkaCommentBody(stringToMarkup(preparsed.body))
127159
Comment(
@@ -144,7 +176,8 @@ abstract class MarkupConversion[T](val repr: Repr)(using DocContext) {
144176
groupDesc = filterEmpty(preparsed.groupDesc).view.mapValues(markupToDokka).to(SortedMap),
145177
groupNames = filterEmpty(preparsed.groupNames).view.mapValues(markupToDokka).to(SortedMap),
146178
groupPrio = preparsed.groupPrio,
147-
hideImplicitConversions = filterEmpty(preparsed.hideImplicitConversions).map(markupToDokka)
179+
hideImplicitConversions = filterEmpty(preparsed.hideImplicitConversions).map(markupToDokka),
180+
snippetCompilerData = getSnippetCompilerData(owner)
148181
)
149182
}
150183

0 commit comments

Comments
 (0)