Skip to content

Commit dc90d29

Browse files
authored
Merge pull request #5 from pikinier20/failing-flag
Add flags: failing, debug. Add addition operation to snippet compiler arg
2 parents 61a74c5 + 5228da3 commit dc90d29

18 files changed

+216
-169
lines changed

project/Build.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@ object Build {
16501650
s"$stdLibRoot=github://scala/scala/v${stdlibVersion(Bootstrapped)}#src/library," +
16511651
s"docs=github://lampepfl/dotty/master#docs",
16521652
"-doc-root-content", docRootFile.toString,
1653-
"-snippet-compiler-args:" +
1653+
"-snippet-compiler:" +
16541654
s"$dottyLibRoot/scala/quoted=nocompile," +
16551655
s"$dottyLibRoot=compile",
16561656
"-Ydocument-synthetic-types"
@@ -1663,7 +1663,11 @@ object Build {
16631663
(Test / Build.testcasesOutputDir).value,
16641664
"scaladoc testcases",
16651665
"scaladoc/output/testcases",
1666-
"master")
1666+
"master",
1667+
Seq(
1668+
"-snippet-compiler-debug"
1669+
)
1670+
)
16671671
}.value,
16681672

16691673
Test / buildInfoKeys := Seq[BuildInfoKey](

scaladoc-testcases/src/tests/snippetCompilerTest.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ package snippetCompiler
77
* a
88
* ```
99
*
10+
* ```scala sc:failing
11+
* def a = 2
12+
* val x = 1 + List()
13+
* a
14+
* ```
15+
*
16+
* ```scala sc:failing
17+
* def a = 2
18+
* ```
19+
*
1020
* ```scala sc:nocompile
1121
* def a = 3
1222
* a()

scaladoc/src/dotty/tools/scaladoc/DocContext.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ case class NavigationNode(name: String, dri: DRI, nested: Seq[NavigationNode])
7171
case class DocContext(args: Scaladoc.Args, compilerContext: CompilerContext):
7272
lazy val sourceLinks = SourceLinks.load(args.sourceLinks, args.revision)(using compilerContext)
7373

74-
lazy val snippetCompilerArgs = snippets.SnippetCompilerArgs.load(args.snippetCompilerArgs)(using compilerContext)
74+
lazy val snippetCompilerArgs = snippets.SnippetCompilerArgs.load(args.snippetCompiler, args.snippetCompilerDebug)(using compilerContext)
7575

7676
lazy val staticSiteContext = args.docsRoot.map(path => StaticSiteContext(
7777
File(path).getAbsoluteFile(),

scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ object Scaladoc:
4444
regexesToSkip: List[String] = Nil,
4545
rootDocPath: Option[String] = None,
4646
documentSyntheticTypes: Boolean = false,
47-
snippetCompilerArgs: List[String] = Nil
47+
snippetCompiler: List[String] = Nil,
48+
snippetCompilerDebug: Boolean = false
4849
)
4950

5051
def run(args: Array[String], rootContext: CompilerContext): Reporter =
@@ -175,7 +176,8 @@ object Scaladoc:
175176
skipByRegex.get,
176177
docRootContent.nonDefault,
177178
YdocumentSyntheticTypes.get,
178-
snippetCompilerArgs.get
179+
snippetCompiler.get,
180+
snippetCompilerDebug.get
179181
)
180182
(Some(docArgs), newContext)
181183
}

scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ class ScaladocSettings extends SettingGroup with CommonScalaSettings:
6060
val YdocumentSyntheticTypes: Setting[Boolean] =
6161
BooleanSetting("-Ydocument-synthetic-types", "Documents intrinsic types e. g. Any, Nothing. Setting is useful only for stdlib", false)
6262

63-
val snippetCompilerArgs: Setting[List[String]] =
64-
MultiStringSetting("-snippet-compiler-args", "snippet-compiler-args", snippets.SnippetCompilerArgs.usage)
63+
val snippetCompiler: Setting[List[String]] =
64+
MultiStringSetting("-snippet-compiler", "snippet-compiler", snippets.SnippetCompilerArgs.usage)
65+
66+
val snippetCompilerDebug: Setting[Boolean] =
67+
BooleanSetting("-snippet-compiler-debug", snippets.SnippetCompilerArgs.debugUsage, false)
6568

6669
def scaladocSpecificSettings: Set[Setting[_]] =
67-
Set(sourceLinks, syntax, revision, externalDocumentationMappings, socialLinks, skipById, skipByRegex, deprecatedSkipPackages, docRootContent, snippetCompilerArgs)
70+
Set(sourceLinks, syntax, revision, externalDocumentationMappings, socialLinks, skipById, skipByRegex, deprecatedSkipPackages, docRootContent, snippetCompiler, snippetCompilerDebug)

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

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

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

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

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

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

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

127123
def mkHead(page: Page): AppliedTag =
128124
val resources = page.content match

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

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ 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._
1312

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

17-
def doc(m: Member): Seq[AppliedTag] = m.docs.fold(Nil)(d => Seq(renderDocPart(d.body)(using m)))
16+
def doc(m: Member): Seq[AppliedTag] = m.docs.fold(Nil)(d => Seq(renderDocPart(d.body)))
1817

1918
def tableRow(name: String, content: AppliedTag) = Seq(dt(name), dd(content))
2019

@@ -38,14 +37,14 @@ class MemberRenderer(signatureRenderer: SignatureRenderer, snippetChecker: Snipp
3837
def nested(name: String, on: SortedMap[String, DocPart]): Seq[AppliedTag] =
3938
if on.isEmpty then Nil else
4039
tableRow(name, dl(cls := "attributes")(
41-
on.map { case (name, value) => tableRow(name, renderDocPart(value)(using m))}.toList:_*
40+
on.map { case (name, value) => tableRow(name, renderDocPart(value))}.toList:_*
4241
))
4342

4443
def list(name: String, on: List[DocPart]): Seq[AppliedTag] =
45-
if on.isEmpty then Nil else tableRow(name, div(on.map(e => div(renderDocPart(e)(using m)))))
44+
if on.isEmpty then Nil else tableRow(name, div(on.map(e => div(renderDocPart(e)))))
4645

4746
def opt(name: String, on: Option[DocPart]): Seq[AppliedTag] =
48-
if on.isEmpty then Nil else tableRow(name, renderDocPart(on.get)(using m))
47+
if on.isEmpty then Nil else tableRow(name, renderDocPart(on.get))
4948

5049
m.docs.fold(Nil)(d =>
5150
nested("Type Params", d.typeParams) ++
@@ -88,17 +87,17 @@ class MemberRenderer(signatureRenderer: SignatureRenderer, snippetChecker: Snipp
8887
Seq(
8988
since.map(s => code("[Since version ", parameter(s), "] ")),
9089
message.map(m => parameter(m)))
91-
++ m.docs.map(_.deprecated.toSeq.map(renderDocPart(_)(using m)))
90+
++ m.docs.map(_.deprecated.toSeq.map(renderDocPart))
9291
).flatten
9392
Seq(dt("Deprecated"), dd(content:_*))
9493
}
9594

9695
def memberInfo(m: Member): Seq[AppliedTag] =
9796
val comment = m.docs
98-
val bodyContents = m.docs.fold(Nil)(e => renderDocPart(e.body)(using m) :: Nil)
97+
val bodyContents = m.docs.fold(Nil)(e => renderDocPart(e.body) :: Nil)
9998

10099
Seq(
101-
div(cls := "documentableBrief doc")(comment.flatMap(_.short).fold("")(renderDocPart(_)(using m))),
100+
div(cls := "documentableBrief doc")(comment.flatMap(_.short).fold("")(renderDocPart)),
102101
div(cls := "cover")(
103102
div(cls := "doc")(bodyContents),
104103
dl(cls := "attributes")(
@@ -248,8 +247,8 @@ class MemberRenderer(signatureRenderer: SignatureRenderer, snippetChecker: Snipp
248247
val rawGroups = membersInGroups.groupBy(_.docs.flatMap(_.group)).collect {
249248
case (Some(groupName), members) =>
250249
ExpandedGroup(
251-
names.get(groupName).fold(raw(groupName))(renderDocPart(_)(using m)),
252-
descriptions.get(groupName).fold(raw(""))(renderDocPart(_)(using m)),
250+
names.get(groupName).fold(raw(groupName))(renderDocPart),
251+
descriptions.get(groupName).fold(raw(""))(renderDocPart),
253252
prios.getOrElse(groupName, 1000)
254253
) -> members
255254
}

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

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,21 @@ import util.HTML._
66
import com.vladsch.flexmark.util.ast.{Node => MdNode}
77
import dotty.tools.scaladoc.tasty.comments.wiki.WikiDocElement
88
import dotty.tools.scaladoc.tasty.comments.markdown.DocFlexmarkRenderer
9-
import dotty.tools.scaladoc.snippets._
109

11-
class DocRender(signatureRenderer: SignatureRenderer, snippetChecker: SnippetChecker)(using ctx: DocContext):
10+
class DocRender(signatureRenderer: SignatureRenderer)(using DocContext):
1211

13-
private val snippetCheckingFuncFromMember: Member => SnippetChecker.SnippetCheckingFunc =
14-
(m: Member) => {
15-
(str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SnippetCompilerArg]) => {
16-
val arg = argOverride.getOrElse(
17-
ctx.snippetCompilerArgs.get(m).getOrElse(SnippetCompilerArg.default)
18-
)
19-
20-
snippetChecker.checkSnippet(str, m.docs.map(_.snippetCompilerData), arg, lineOffset).foreach { _ match {
21-
case r @ SnippetCompilationResult(None, _) =>
22-
println(s"In member ${m.name} (${m.dri.location}):")
23-
println(r.getSummary)
24-
case _ =>
25-
}
26-
}
27-
}
28-
}
29-
30-
def renderDocPart(doc: DocPart)(using Member): AppliedTag = doc match
12+
def renderDocPart(doc: DocPart): AppliedTag = doc match
3113
case md: MdNode => renderMarkdown(md)
3214
case Nil => raw("")
3315
case Seq(elem: WikiDocElement) => renderElement(elem)
3416
case list: Seq[WikiDocElement @unchecked] => div(list.map(renderElement))
3517

36-
private def renderMarkdown(el: MdNode)(using m: Member): AppliedTag =
37-
raw(DocFlexmarkRenderer.render(el)(
38-
(link,name) =>
39-
renderLink(link, default => text(if name.isEmpty then default else name)).toString,
40-
snippetCheckingFuncFromMember(m)
18+
private def renderMarkdown(el: MdNode): AppliedTag =
19+
raw(DocFlexmarkRenderer.render(el)( (link,name) =>
20+
renderLink(link, default => text(if name.isEmpty then default else name)).toString
4121
))
4222

43-
private def listItems(items: Seq[WikiDocElement])(using m: Member) =
23+
private def listItems(items: Seq[WikiDocElement]) =
4424
items.map(i => li(renderElement(i)))
4525
private def notSupported(name: String, content: AppliedTag): AppliedTag =
4626
report.warning(s"Wiki syntax does not support $name in ${signatureRenderer.currentDri.location}")
@@ -55,7 +35,7 @@ class DocRender(signatureRenderer: SignatureRenderer, snippetChecker: SnippetChe
5535
val tooltip = s"Problem linking $query: $msg"
5636
signatureRenderer.unresolvedLink(linkBody(query), titleAttr := tooltip)
5737

58-
private def renderElement(e: WikiDocElement)(using m: Member): AppliedTag = e match
38+
private def renderElement(e: WikiDocElement): AppliedTag = e match
5939
case Title(text, level) =>
6040
val content = renderElement(text)
6141
level match
@@ -66,9 +46,7 @@ class DocRender(signatureRenderer: SignatureRenderer, snippetChecker: SnippetChe
6646
case 5 => h5(content)
6747
case 6 => h6(content)
6848
case Paragraph(text) => p(renderElement(text))
69-
case Code(data: String) =>
70-
snippetCheckingFuncFromMember(m)(data, 0, None)
71-
pre(code(raw(data))) // TODO add classes
49+
case Code(data: String) => pre(code(raw(data))) // TODO add classes
7250
case HorizontalRule => hr
7351

7452
case UnorderedList(items) => ul(listItems(items))

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

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,13 @@ class SnippetChecker()(using ctx: DocContext):
1111
ctx.args.tastyDirs.map(_.getAbsolutePath()).mkString(sep)
1212
private val compiler: SnippetCompiler = SnippetCompiler(classpath = cp)
1313

14-
var warningsCount = 0
15-
var errorsCount = 0
16-
1714
def checkSnippet(
1815
snippet: String,
1916
data: Option[SnippetCompilerData],
2017
arg: SnippetCompilerArg,
2118
lineOffset: SnippetChecker.LineOffset
2219
): Option[SnippetCompilationResult] = {
23-
if arg.is(SCFlags.Compile) then
20+
if arg.flag != SCFlags.NoCompile then
2421
val wrapped = WrappedSnippet(
2522
snippet,
2623
data.map(_.packageName),
@@ -30,19 +27,11 @@ class SnippetChecker()(using ctx: DocContext):
3027
lineOffset + data.fold(0)(_.position.line) + 1,
3128
data.fold(0)(_.position.column)
3229
)
33-
val res = compiler.compile(wrapped)
34-
if !res.messages.filter(_.level == MessageLevel.Error).isEmpty then errorsCount = errorsCount + 1
35-
if !res.messages.filter(_.level == MessageLevel.Warning).isEmpty then warningsCount = warningsCount + 1
30+
val res = compiler.compile(wrapped, arg)
3631
Some(res)
3732
else None
3833
}
3934

40-
def summary: String = s"""
41-
|Snippet compiler summary:
42-
| Found $warningsCount warnings
43-
| Found $errorsCount errors
44-
|""".stripMargin
45-
4635
object SnippetChecker:
4736
type LineOffset = Int
48-
type SnippetCheckingFunc = (String, LineOffset, Option[SnippetCompilerArg]) => Unit
37+
type SnippetCheckingFunc = (String, LineOffset, Option[SCFlags]) => Option[SnippetCompilationResult]

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,29 @@ package snippets
33

44
import dotty.tools.io.{ AbstractFile }
55

6-
case class SnippetCompilerMessage(line: Int, column: Int, sourceLine: String, message: String, level: MessageLevel)
6+
case class Position(line: Int, column: Int, sourceLine: String)
77

8-
case class SnippetCompilationResult(result: Option[AbstractFile], messages: Seq[SnippetCompilerMessage]):
9-
def getSummary: String = messages.map(m => s"At ${m.line}:${m.column}:\n${m.sourceLine}${m.level.text}: ${m.message}").mkString("\n")
8+
case class SnippetCompilerMessage(position: Option[Position], message: String, level: MessageLevel)
9+
10+
case class SnippetCompilationResult(
11+
wrappedSnippet: String,
12+
isSuccessful: Boolean,
13+
result: Option[AbstractFile],
14+
messages: Seq[SnippetCompilerMessage]
15+
):
16+
def getSummary: String =
17+
messages.map(m =>
18+
m.position.fold(
19+
s"${m.level.text}: ${m.message}"
20+
)(pos =>
21+
s"At ${pos.line}:${pos.column}:\n${pos.sourceLine}${m.level.text}: ${m.message}"
22+
)
23+
).mkString("\n")
1024

1125

1226
enum MessageLevel(val text: String):
1327
case Info extends MessageLevel("Info")
1428
case Warning extends MessageLevel("Warning")
1529
case Error extends MessageLevel("Error")
30+
case Debug extends MessageLevel("Debug")
1631

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,34 @@ class SnippetCompiler(
4646
val infos = diagnostics.toSeq.sortBy(_.pos.source.path)
4747
val errorMessages = infos.map {
4848
case diagnostic if diagnostic.position.isPresent =>
49-
val pos = diagnostic.position.get
49+
val diagPos = diagnostic.position.get
50+
val pos = Some(
51+
Position(diagPos.line + line, diagPos.column + column, diagPos.lineContent)
52+
)
5053
val msg = nullableMessage(diagnostic.message)
5154
val level = MessageLevel.fromOrdinal(diagnostic.level)
52-
SnippetCompilerMessage(pos.line + line, pos.column + column, pos.lineContent, msg, level)
55+
SnippetCompilerMessage(pos, msg, level)
5356
case d =>
5457
val level = MessageLevel.fromOrdinal(d.level)
55-
SnippetCompilerMessage(-1, -1, "", nullableMessage(d.message), level)
58+
SnippetCompilerMessage(None, nullableMessage(d.message), level)
5659
}
5760
errorMessages
5861
}
5962

63+
private def additionalMessages(wrappedSnippet: WrappedSnippet, arg: SnippetCompilerArg, context: Context): Seq[SnippetCompilerMessage] = {
64+
Option.when(arg.flag == SCFlags.Fail && !context.reporter.hasErrors)(
65+
SnippetCompilerMessage(None, "Snippet should not compile but compiled succesfully", MessageLevel.Error)
66+
).toList
67+
}
68+
69+
private def isSuccessful(arg: SnippetCompilerArg, context: Context): Boolean = {
70+
if arg.flag == SCFlags.Fail then context.reporter.hasErrors
71+
else !context.reporter.hasErrors
72+
}
73+
6074
def compile(
61-
wrappedSnippet: WrappedSnippet
75+
wrappedSnippet: WrappedSnippet,
76+
arg: SnippetCompilerArg
6277
): SnippetCompilationResult = {
6378
val context = driver.currentCtx.fresh
6479
.setSetting(
@@ -68,7 +83,11 @@ class SnippetCompiler(
6883
.setReporter(new StoreReporter)
6984
val run = newRun(using context)
7085
run.compileFromStrings(List(wrappedSnippet.snippet))
71-
val messages = createReportMessage(context.reporter.pendingMessages(using context), wrappedSnippet.lineOffset, wrappedSnippet.columnOffset)
72-
val targetIfSuccessful = Option.when(!context.reporter.hasErrors)(target)
73-
SnippetCompilationResult(targetIfSuccessful, messages)
86+
87+
val messages =
88+
createReportMessage(context.reporter.pendingMessages(using context), wrappedSnippet.lineOffset, wrappedSnippet.columnOffset) ++
89+
additionalMessages(wrappedSnippet, arg, context)
90+
91+
val t = Option.when(!context.reporter.hasErrors)(target)
92+
SnippetCompilationResult(wrappedSnippet.snippet, isSuccessful(arg, context), t, messages)
7493
}

0 commit comments

Comments
 (0)