From c5dccd87cc603dc0b5096bdd1543805d2fb797b3 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Fri, 12 Dec 2025 00:37:39 +0100 Subject: [PATCH 1/5] Allow to set scala compiler options on snipets. Use the extra scalacOptions in snippet compiler --- .../src/dotty/tools/scaladoc/site/templates.scala | 4 ++-- .../snippets/FlexmarkSnippetProcessor.scala | 15 ++++++++++++++- .../tools/scaladoc/snippets/SnippetChecker.scala | 2 +- .../tools/scaladoc/snippets/SnippetCompiler.scala | 9 ++++++++- .../scaladoc/snippets/SnippetCompilerArgs.scala | 5 ++++- .../tools/scaladoc/tasty/comments/Comments.scala | 4 ++-- 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 56a0f7f6d6b6..6d5eeb06267a 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -81,8 +81,8 @@ case class TemplateFile( val path = Some(Paths.get(file.getAbsolutePath)) val pathBasedArg = ssctx.snippetCompilerArgs.get(path) val sourceFile = dotty.tools.dotc.util.SourceFile(dotty.tools.io.AbstractFile.getFile(path.get), scala.io.Codec.UTF8) - (str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SCFlags]) => { - val arg = argOverride.fold(pathBasedArg)(pathBasedArg.overrideFlag(_)) + (str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SnippetCompilerArg]) => { + val arg = argOverride.fold(pathBasedArg)(pathBasedArg.merge(_)) val compilerData = SnippetCompilerData( "staticsitesnippet", SnippetCompilerData.Position(configOffset - 1, 0) diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala index c92853816d16..75a280376f50 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala @@ -21,7 +21,7 @@ object FlexmarkSnippetProcessor: val lineOffset = node.getStartLineNumber + preparsed.fold(0)(_.strippedLinesBeforeNo) val info = node.getInfo.toString.split(" ") if info.contains("scala") then { - val argOverride = info + val flagOverride = info .find(_.startsWith("sc:")) .map(_.stripPrefix("sc:")) .map(SCFlagsParser.parse) @@ -34,6 +34,19 @@ object FlexmarkSnippetProcessor: ) None }) + + val scalacOptions = info + .filter(_.startsWith("sc-opts:")) + .map(_.stripPrefix("sc-opts:")) + .toSeq + + val argOverride: Option[SnippetCompilerArg] = + (flagOverride, scalacOptions) match { + case (None, Seq()) => None + case (Some(flag), opts) => Some(SnippetCompilerArg(flag, opts)) + case (None, opts) => Some(SnippetCompilerArg(SCFlags.Compile, opts)) + } + val id = info .find(_.startsWith("sc-name:")) .map(_.stripPrefix("sc-name:")) diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala index 8f8b73a576d1..4f90fbcee984 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala @@ -59,4 +59,4 @@ class SnippetChecker(val args: Scaladoc.Args)(using cctx: CompilerContext): object SnippetChecker: type LineOffset = Int - type SnippetCheckingFunc = (String, LineOffset, Option[SCFlags]) => Option[SnippetCompilationResult] + type SnippetCheckingFunc = (String, LineOffset, Option[SnippetCompilerArg]) => Option[SnippetCompilationResult] diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala index b13b5e9756ea..971e7ec6357c 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala @@ -100,12 +100,19 @@ class SnippetCompiler( arg: SnippetCompilerArg, sourceFile: SourceFile ): SnippetCompilationResult = { - val context = SnippetDriver.currentCtx.fresh + val baseContext = SnippetDriver.currentCtx.fresh .setSetting( SnippetDriver.currentCtx.settings.outputDir, target ) .setReporter(new StoreReporter) + val context = + if arg.scalacOptions.isEmpty then baseContext + else + val args = arg.scalacOptions.toArray + SnippetDriver.setup(args, baseContext) match + case Some((_, ctx)) => ctx + case None => baseContext val run = newRun(using context) run.compileFromStrings(List(wrappedSnippet.snippet)) diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerArgs.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerArgs.scala index 35a89d985d8e..b5a3f7dfe123 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerArgs.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerArgs.scala @@ -3,8 +3,11 @@ package snippets import java.nio.file.Path -case class SnippetCompilerArg(flag: SCFlags): +case class SnippetCompilerArg(flag: SCFlags, scalacOptions: Seq[String] = Seq.empty): def overrideFlag(f: SCFlags): SnippetCompilerArg = copy(flag = f) + def withScalacOptions(opts: Seq[String]): SnippetCompilerArg = copy(scalacOptions = scalacOptions ++ opts) + def merge(other: SnippetCompilerArg): SnippetCompilerArg = + SnippetCompilerArg(other.flag, scalacOptions ++ other.scalacOptions) enum SCFlags(val flagName: String): case Compile extends SCFlags("compile") diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala index 5b72e9eb5c42..9659bce44369 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala @@ -137,8 +137,8 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) { val scDataCollector = SnippetCompilerDataCollector[qctx.type](qctx) val data = scDataCollector.getSnippetCompilerData(s, s) val sourceFile = scDataCollector.getSourceFile(s) - (str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SCFlags]) => { - val arg = argOverride.fold(pathBasedArg)(pathBasedArg.overrideFlag(_)) + (str: String, lineOffset: SnippetChecker.LineOffset, argOverride: Option[SnippetCompilerArg]) => { + val arg = argOverride.fold(pathBasedArg)(pathBasedArg.merge(_)) val res = snippetChecker.checkSnippet(str, Some(data), arg, lineOffset, sourceFile) res.filter(r => !r.isSuccessful).foreach(_.reportMessages()(using compilerContext)) res From 0fbd67eaa0bcfa5c3f4b04c10bca820131635101 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Fri, 12 Dec 2025 00:38:42 +0100 Subject: [PATCH 2/5] Show position of code snippets that failed to compile --- .../src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala index 971e7ec6357c..780eea53c10b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala @@ -86,7 +86,9 @@ class SnippetCompiler( private def additionalMessages(wrappedSnippet: WrappedSnippet, arg: SnippetCompilerArg, sourceFile: SourceFile, context: Context): Seq[SnippetCompilerMessage] = { Option.when(arg.flag == SCFlags.Fail && !context.reporter.hasErrors)( - SnippetCompilerMessage(None, "Snippet should not compile but compiled successfully", MessageLevel.Error) + SnippetCompilerMessage( + Some(Position(SourcePosition(sourceFile, NoSpan), wrappedSnippet.outerLineOffset)), + "Snippet should not compile but compiled successfully", MessageLevel.Error) ).toList } From 86b52b72f7c5636e09342bb11c64d798e8f2f217 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 14 Dec 2025 19:05:59 +0100 Subject: [PATCH 3/5] Fix passing multiple setting using sc-opts in snippets to SnippetCompiler --- .../tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala index 75a280376f50..f6c6fca1aabc 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala @@ -35,10 +35,10 @@ object FlexmarkSnippetProcessor: None }) - val scalacOptions = info + val scalacOptions: Seq[String] = info .filter(_.startsWith("sc-opts:")) - .map(_.stripPrefix("sc-opts:")) - .toSeq + .map(_.stripPrefix("sc-opts:").split(",").map(_.trim).toSeq) + .flatten val argOverride: Option[SnippetCompilerArg] = (flagOverride, scalacOptions) match { From 3051bb2bf620c8ff5493ec58ce63b0289a8273d9 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 14 Dec 2025 21:23:20 +0100 Subject: [PATCH 4/5] Fix deprecation warning in FlexmarkSnippetProcessor --- .../tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala index f6c6fca1aabc..a40ae317e135 100644 --- a/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala +++ b/scaladoc/src/dotty/tools/scaladoc/snippets/FlexmarkSnippetProcessor.scala @@ -36,9 +36,9 @@ object FlexmarkSnippetProcessor: }) val scalacOptions: Seq[String] = info + .toIndexedSeq .filter(_.startsWith("sc-opts:")) - .map(_.stripPrefix("sc-opts:").split(",").map(_.trim).toSeq) - .flatten + .flatMap(_.stripPrefix("sc-opts:").split(",").map(_.trim).toSeq) val argOverride: Option[SnippetCompilerArg] = (flagOverride, scalacOptions) match { From 58bb69727b88bbf9e693a2f4aa69da8845445938 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 14 Dec 2025 21:45:18 +0100 Subject: [PATCH 5/5] Add tet case to ensure sc-opts are passed to snippet compiler --- scaladoc-testcases/docs/_docs/index.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scaladoc-testcases/docs/_docs/index.md b/scaladoc-testcases/docs/_docs/index.md index 9acac71a63b3..f11b5d31b7dd 100644 --- a/scaladoc-testcases/docs/_docs/index.md +++ b/scaladoc-testcases/docs/_docs/index.md @@ -22,3 +22,14 @@ val renderer: Renderer = Renderer() extension (x: Self) def combine(y: Self): Self ``` +```scala sc:fail sc-opts:-Werror:true +def exampleShouldError(input: Option[String]): Unit = + input match + case Some("foo") => ??? +``` + +```scala sc:compile sc-opts:-Werror:false +def exampleShouldWarn(input: Option[String]): Unit = + input match + case Some("foo") => ??? +``` \ No newline at end of file