diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala
index fe17973ecda8..09980ea96f60 100644
--- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala
@@ -68,6 +68,7 @@ case class TemplateFile(
lazy val snippetCheckingFunc: SnippetChecker.SnippetCheckingFunc =
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(_))
val compilerData = SnippetCompilerData(
@@ -76,10 +77,9 @@ case class TemplateFile(
Nil,
SnippetCompilerData.Position(configOffset - 1, 0)
)
- ssctx.snippetChecker.checkSnippet(str, Some(compilerData), arg, lineOffset).collect {
+ ssctx.snippetChecker.checkSnippet(str, Some(compilerData), arg, lineOffset, sourceFile).collect {
case r: SnippetCompilationResult if !r.isSuccessful =>
- val msg = s"In static site (${file.getAbsolutePath}):\n${r.getSummary}"
- report.error(msg)(using ssctx.outerCtx)
+ r.reportMessages()(using ssctx.outerCtx)
r
case r => r
}
diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala
index 763821d0de59..46869b7114b3 100644
--- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetChecker.scala
@@ -5,6 +5,7 @@ import dotty.tools.scaladoc.DocContext
import java.nio.file.Paths
import java.io.File
+import dotty.tools.dotc.util.SourceFile
import dotty.tools.io.AbstractFile
import dotty.tools.dotc.fromtasty.TastyFileUtil
import dotty.tools.dotc.config.Settings._
@@ -39,7 +40,8 @@ class SnippetChecker(val args: Scaladoc.Args)(using cctx: CompilerContext):
snippet: String,
data: Option[SnippetCompilerData],
arg: SnippetCompilerArg,
- lineOffset: SnippetChecker.LineOffset
+ lineOffset: SnippetChecker.LineOffset,
+ sourceFile: SourceFile
): Option[SnippetCompilationResult] = {
if arg.flag != SCFlags.NoCompile then
val wrapped = WrappedSnippet(
@@ -50,7 +52,7 @@ class SnippetChecker(val args: Scaladoc.Args)(using cctx: CompilerContext):
lineOffset + data.fold(0)(_.position.line) + constantLineOffset,
data.fold(0)(_.position.column) + constantColumnOffset
)
- val res = compiler.compile(wrapped, arg)
+ val res = compiler.compile(wrapped, arg, sourceFile)
Some(res)
else None
}
diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilationResult.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilationResult.scala
index f4fe2f8223fb..4df5922c1690 100644
--- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilationResult.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilationResult.scala
@@ -2,14 +2,11 @@ package dotty.tools.scaladoc
package snippets
import dotty.tools.io.{ AbstractFile }
+import dotty.tools.dotc.util.{ SourcePosition, SrcPos }
-case class Position(line: Int, column: Int, sourceLine: String, relativeLine: Int)
+case class Position(srcPos: SourcePosition, relativeLine: Int)
-case class SnippetCompilerMessage(position: Option[Position], message: String, level: MessageLevel):
- def getSummary: String =
- position.fold(s"${level.text}: ${message}") { pos =>
- s"At ${pos.line}:${pos.column}:\n${pos.sourceLine}${level.text}: ${message}"
- }
+case class SnippetCompilerMessage(position: Option[Position], message: String, level: MessageLevel)
case class SnippetCompilationResult(
wrappedSnippet: WrappedSnippet,
@@ -17,7 +14,16 @@ case class SnippetCompilationResult(
result: Option[AbstractFile],
messages: Seq[SnippetCompilerMessage]
):
- def getSummary: String = messages.map(_.getSummary).mkString("\n")
+ def reportMessages()(using CompilerContext) = messages.foreach {
+ case SnippetCompilerMessage(posOpt, msg, level) =>
+ val pos: SrcPos = posOpt.fold(dotty.tools.dotc.util.NoSourcePosition)(_.srcPos)
+ level match {
+ case MessageLevel.Info => report.log(msg, pos)
+ case MessageLevel.Warning => report.warning(msg, pos)
+ case MessageLevel.Error => report.error(msg, pos)
+ case MessageLevel.Debug => report.log(msg, pos)
+ }
+ }
enum MessageLevel(val text: String):
case Info extends MessageLevel("Info")
diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala
index 00f89b94c626..1e741f421d1b 100644
--- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompiler.scala
@@ -6,7 +6,7 @@ import dotty.tools.dotc.Driver
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Mode
import dotty.tools.dotc.config.Settings.Setting._
-import dotty.tools.dotc.interfaces.SourcePosition
+import dotty.tools.dotc.interfaces.{ SourcePosition => ISourcePosition }
import dotty.tools.dotc.ast.Trees.Tree
import dotty.tools.dotc.interfaces.{SourceFile => ISourceFile}
import dotty.tools.dotc.reporting.{ Diagnostic, StoreReporter }
@@ -14,8 +14,9 @@ import dotty.tools.dotc.parsing.Parsers.Parser
import dotty.tools.dotc.{ Compiler, Run }
import dotty.tools.io.{AbstractFile, VirtualDirectory}
import dotty.tools.repl.AbstractFileClassLoader
-import dotty.tools.dotc.util.SourceFile
+import dotty.tools.dotc.util.Spans._
import dotty.tools.dotc.interfaces.Diagnostic._
+import dotty.tools.dotc.util.{ SourcePosition, NoSourcePosition, SourceFile, NoSource }
import scala.util.{ Try, Success, Failure }
@@ -49,7 +50,7 @@ class SnippetCompiler(
private def nullableMessage(msgOrNull: String): String =
if (msgOrNull == null) "" else msgOrNull
- private def createReportMessage(wrappedSnippet: WrappedSnippet, arg: SnippetCompilerArg, diagnostics: Seq[Diagnostic]): Seq[SnippetCompilerMessage] = {
+ private def createReportMessage(wrappedSnippet: WrappedSnippet, arg: SnippetCompilerArg, diagnostics: Seq[Diagnostic], sourceFile: SourceFile): Seq[SnippetCompilerMessage] = {
val line = wrappedSnippet.outerLineOffset
val column = wrappedSnippet.outerColumnOffset
val innerLineOffset = wrappedSnippet.innerLineOffset
@@ -57,9 +58,16 @@ class SnippetCompiler(
val infos = diagnostics.toSeq.sortBy(_.pos.source.path)
val errorMessages = infos.map {
case diagnostic if diagnostic.position.isPresent =>
- val diagPos = diagnostic.position.get
+ val diagPos = diagnostic.position.get match
+ case s: SourcePosition => s
+ case _ => NoSourcePosition
+ val offsetFromLine = sourceFile match
+ case NoSource => 0
+ case sf: SourceFile => sf.lineToOffset(diagPos.line + line - innerLineOffset - 1)
+ val offsetFromColumn = diagPos.column + column - innerColumnOffset
+ val span = Span(offsetFromLine + offsetFromColumn, offsetFromLine + offsetFromColumn)
val pos = Some(
- Position(diagPos.line + line - innerLineOffset, diagPos.column + column - innerColumnOffset, diagPos.lineContent, diagPos.line)
+ Position(dotty.tools.dotc.util.SourcePosition(sourceFile, span), diagPos.line)
)
val dmsg = Try(diagnostic.message) match {
case Success(msg) => msg
@@ -75,7 +83,7 @@ class SnippetCompiler(
errorMessages
}
- private def additionalMessages(wrappedSnippet: WrappedSnippet, arg: SnippetCompilerArg, context: Context): Seq[SnippetCompilerMessage] = {
+ 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 succesfully", MessageLevel.Error)
).toList
@@ -88,7 +96,8 @@ class SnippetCompiler(
def compile(
wrappedSnippet: WrappedSnippet,
- arg: SnippetCompilerArg
+ arg: SnippetCompilerArg,
+ sourceFile: SourceFile
): SnippetCompilationResult = {
val context = SnippetDriver.currentCtx.fresh
.setSetting(
@@ -100,8 +109,8 @@ class SnippetCompiler(
run.compileFromStrings(List(wrappedSnippet.snippet))
val messages =
- createReportMessage(wrappedSnippet, arg, context.reporter.pendingMessages(using context)) ++
- additionalMessages(wrappedSnippet, arg, context)
+ createReportMessage(wrappedSnippet, arg, context.reporter.pendingMessages(using context), sourceFile) ++
+ additionalMessages(wrappedSnippet, arg, sourceFile, context)
val t = Option.when(!context.reporter.hasErrors)(target)
SnippetCompilationResult(wrappedSnippet, isSuccessful(arg, context), t, messages)
diff --git a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala
index 475d38fef895..c1629f8d35cc 100644
--- a/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/snippets/SnippetCompilerDataCollector.scala
@@ -4,11 +4,20 @@ package snippets
import scala.quoted._
import dotty.tools.scaladoc.tasty.SymOps._
import dotty.tools.dotc.core._
+import dotty.tools.dotc.util.{ SourceFile => CSourceFile, NoSource }
class SnippetCompilerDataCollector[Q <: Quotes](val qctx: Q):
import qctx.reflect._
given qctx.type = qctx
+ def getSourceFile(sym: Symbol): CSourceFile =
+ given ctx: Contexts.Context = qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
+ sym match
+ case csym: Symbols.Symbol => csym.source(using ctx)
+ case _ =>
+ report.warning(s"Can't cast symbol $sym to compiler symbol. This is a bug of snippet compiler, please create an issue on dotty repository.")
+ NoSource
+
def getSnippetCompilerData(sym: Symbol, originalSym: Symbol): SnippetCompilerData =
val packageName = sym.packageName
if !sym.isPackageDef then sym.tree match {
diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala
index bcd7dfcb438d..1481f13f15f5 100644
--- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala
@@ -128,17 +128,14 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) {
(s: qctx.reflect.Symbol) => {
val path = s.source.map(_.path)
val pathBasedArg = dctx.snippetCompilerArgs.get(path)
- val data = SnippetCompilerDataCollector[qctx.type](qctx).getSnippetCompilerData(s, s)
+ 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(_))
-
- snippetChecker.checkSnippet(str, Some(data), arg, lineOffset).collect {
- case r: SnippetCompilationResult if !r.isSuccessful =>
- val msg = s"In member ${s.name} (${s.dri.location}):\n${r.getSummary}"
- report.error(msg)(using dctx.compilerContext)
- r
- case r => r
- }
+ val res = snippetChecker.checkSnippet(str, Some(data), arg, lineOffset, sourceFile)
+ res.filter(r => !r.isSuccessful).foreach(_.reportMessages()(using compilerContext))
+ res
}
}
diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala
index dd87527625d5..634e76e6ef3f 100644
--- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala
+++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala
@@ -125,7 +125,7 @@ object SnippetRenderer:
else
val content = messages
.map { msg =>
- s"""${msg.getSummary}"""
+ s"""${msg.message}"""
}
.mkString("
")
s"""