From fa2c3a3d5d038379dbd8b549c833572f3421b98f Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Jul 2025 19:26:34 +0200 Subject: [PATCH] bugfix: Also save infos in semannticdb Previously, when user changed a warning to info, we would not save it and miss information if that warning was about unused. Now, we also save infos. --- .../dotty/tools/dotc/reporting/Reporter.scala | 10 ++- .../dotc/semanticdb/ExtractSemanticDB.scala | 10 +-- .../semanticdb/expect/InfoMacro.expect.scala | 14 ++++ tests/semanticdb/expect/InfoMacro.scala | 14 ++++ .../expect/InfoMacroTest.expect.scala | 7 ++ tests/semanticdb/expect/InfoMacroTest.scala | 7 ++ tests/semanticdb/metac.expect | 83 +++++++++++++++++++ 7 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 tests/semanticdb/expect/InfoMacro.expect.scala create mode 100644 tests/semanticdb/expect/InfoMacro.scala create mode 100644 tests/semanticdb/expect/InfoMacroTest.expect.scala create mode 100644 tests/semanticdb/expect/InfoMacroTest.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 61f842800b78..aadac68b37e1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -95,6 +95,7 @@ abstract class Reporter extends interfaces.ReporterResult { private var _errorCount = 0 private var _warningCount = 0 + private var _infoCount = 0 /** The number of errors reported by this reporter (ignoring outer reporters) */ def errorCount: Int = _errorCount @@ -112,12 +113,17 @@ abstract class Reporter extends interfaces.ReporterResult { private var warnings: List[Warning] = Nil + private var infos: List[Info] = Nil + /** All errors reported by this reporter (ignoring outer reporters) */ def allErrors: List[Error] = errors /** All warnings reported by this reporter (ignoring outer reporters) */ def allWarnings: List[Warning] = warnings + /** All infos reported by this reporter (ignoring outer reporters) */ + def allInfos: List[Info] = infos + /** Were sticky errors reported? Overridden in StoreReporter. */ def hasStickyErrors: Boolean = false @@ -171,7 +177,9 @@ abstract class Reporter extends interfaces.ReporterResult { _errorCount += 1 if ctx.typerState.isGlobalCommittable then ctx.base.errorsToBeReported = true - case _: Info => // nothing to do here + case i: Info => + infos = i :: infos + _infoCount += 1 // match error if d is something else } markReported(dia) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 3768ce6ce1e0..b07963b28182 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -63,7 +63,7 @@ class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode) extends private def computeDiagnostics( sourceRoot: String, - warnings: Map[SourceFile, List[Warning]], + warnings: Map[SourceFile, List[dotty.tools.dotc.reporting.Diagnostic]], append: ((Path, List[Diagnostic])) => Unit)(using Context): Boolean = monitor(phaseName) { val unit = ctx.compilationUnit warnings.get(unit.source).foreach { ws => @@ -104,14 +104,14 @@ class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode) extends val appendDiagnostics = phaseMode == ExtractSemanticDB.PhaseMode.AppendDiagnostics val unitContexts = units.map(ctx.fresh.setCompilationUnit(_).withRootImports) if (appendDiagnostics) - val warnings = ctx.reporter.allWarnings.groupBy(w => w.pos.source) + val warningsAndInfos = (ctx.reporter.allWarnings ++ ctx.reporter.allInfos).groupBy(w => w.pos.source) val buf = mutable.ListBuffer.empty[(Path, Seq[Diagnostic])] val units0 = - for unitCtx <- unitContexts if computeDiagnostics(sourceRoot, warnings, buf += _)(using unitCtx) + for unitCtx <- unitContexts if computeDiagnostics(sourceRoot, warningsAndInfos, buf += _)(using unitCtx) yield unitCtx.compilationUnit cancellable { - buf.toList.asJava.parallelStream().forEach { case (out, warnings) => - ExtractSemanticDB.appendDiagnostics(warnings, out) + buf.toList.asJava.parallelStream().forEach { case (out, diagnostics) => + ExtractSemanticDB.appendDiagnostics(diagnostics, out) } } units0 diff --git a/tests/semanticdb/expect/InfoMacro.expect.scala b/tests/semanticdb/expect/InfoMacro.expect.scala new file mode 100644 index 000000000000..67122d6cbf37 --- /dev/null +++ b/tests/semanticdb/expect/InfoMacro.expect.scala @@ -0,0 +1,14 @@ +import scala.quoted.* + +object InfoMacro/*<-_empty_::InfoMacro.*/ { + inline def reportInfo/*<-_empty_::InfoMacro.reportInfo().*/(msg/*<-_empty_::InfoMacro.reportInfo().(msg)*/: String/*->scala::Predef.String#*/): Unit/*->scala::Unit#*/ = ${ reportInfoMacro/*->_empty_::InfoMacro.reportInfoMacro().*/('msg) } + + def reportInfoMacro/*<-_empty_::InfoMacro.reportInfoMacro().*/(msg/*<-_empty_::InfoMacro.reportInfoMacro().(msg)*/: Expr/*->scala::quoted::Expr#*/[String/*->scala::Predef.String#*/])(using Quotes/*->scala::quoted::Quotes#*/): Expr/*->scala::quoted::Expr#*/[Unit/*->scala::Unit#*/] = { + import quotes/*->scala::quoted::Quotes$package.quotes().*/.reflect/*->scala::quoted::Quotes#reflect.*/.report/*->scala::quoted::Quotes#reflectModule#report.*/ + + // Report an info diagnostic + report/*->scala::quoted::Quotes#reflectModule#report.*/.info/*->scala::quoted::Quotes#reflectModule#reportModule#info().*/(s/*->scala::StringContext#s().*/"Info from macro: ${msg/*->_empty_::InfoMacro.reportInfoMacro().(msg)*/.valueOrAbort/*->scala::quoted::Quotes#valueOrAbort().*/}") + + '{ () } + } +} diff --git a/tests/semanticdb/expect/InfoMacro.scala b/tests/semanticdb/expect/InfoMacro.scala new file mode 100644 index 000000000000..9248d51dd03a --- /dev/null +++ b/tests/semanticdb/expect/InfoMacro.scala @@ -0,0 +1,14 @@ +import scala.quoted.* + +object InfoMacro { + inline def reportInfo(msg: String): Unit = ${ reportInfoMacro('msg) } + + def reportInfoMacro(msg: Expr[String])(using Quotes): Expr[Unit] = { + import quotes.reflect.report + + // Report an info diagnostic + report.info(s"Info from macro: ${msg.valueOrAbort}") + + '{ () } + } +} diff --git a/tests/semanticdb/expect/InfoMacroTest.expect.scala b/tests/semanticdb/expect/InfoMacroTest.expect.scala new file mode 100644 index 000000000000..19977da0c79f --- /dev/null +++ b/tests/semanticdb/expect/InfoMacroTest.expect.scala @@ -0,0 +1,7 @@ + +object InfoMacroTest/*<-_empty_::InfoMacroTest.*/ { + def main/*<-_empty_::InfoMacroTest.main().*/(): Unit/*->scala::Unit#*/ = { + InfoMacro/*->_empty_::InfoMacro.*/.reportInfo/*->_empty_::InfoMacro.reportInfo().*/("This is a test info message") + InfoMacro/*->_empty_::InfoMacro.*/.reportInfo/*->_empty_::InfoMacro.reportInfo().*/("Another info message") + } +} diff --git a/tests/semanticdb/expect/InfoMacroTest.scala b/tests/semanticdb/expect/InfoMacroTest.scala new file mode 100644 index 000000000000..e53a840efc8a --- /dev/null +++ b/tests/semanticdb/expect/InfoMacroTest.scala @@ -0,0 +1,7 @@ + +object InfoMacroTest { + def main(): Unit = { + InfoMacro.reportInfo("This is a test info message") + InfoMacro.reportInfo("Another info message") + } +} diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 3f904b6bdda0..c4f02eaadc78 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -2007,6 +2007,89 @@ Occurrences: Diagnostics: [0:26..0:34): [warning] unused import +expect/InfoMacro.scala +---------------------- + +Summary: +Schema => SemanticDB v4 +Uri => InfoMacro.scala +Text => empty +Language => Scala +Symbols => 7 entries +Occurrences => 23 entries +Synthetics => 6 entries + +Symbols: +_empty_/InfoMacro. => final object InfoMacro extends Object { self: InfoMacro.type => +3 decls } +_empty_/InfoMacro.reportInfo(). => inline macro reportInfo (param msg: String): Unit +_empty_/InfoMacro.reportInfo().(msg) => param msg: String +_empty_/InfoMacro.reportInfoMacro(). => method reportInfoMacro (param msg: Expr[String])(implicit given param x$2: Quotes): Expr[Unit] +_empty_/InfoMacro.reportInfoMacro().(msg) => param msg: Expr[String] +_empty_/InfoMacro.reportInfoMacro().(x$2) => implicit given param x$2: Quotes +local0 => implicit given param contextual$1: Quotes + +Occurrences: +[0:7..0:12): scala -> scala/ +[0:13..0:19): quoted -> scala/quoted/ +[2:7..2:16): InfoMacro <- _empty_/InfoMacro. +[3:13..3:23): reportInfo <- _empty_/InfoMacro.reportInfo(). +[3:24..3:27): msg <- _empty_/InfoMacro.reportInfo().(msg) +[3:29..3:35): String -> scala/Predef.String# +[3:38..3:42): Unit -> scala/Unit# +[3:48..3:63): reportInfoMacro -> _empty_/InfoMacro.reportInfoMacro(). +[5:6..5:21): reportInfoMacro <- _empty_/InfoMacro.reportInfoMacro(). +[5:22..5:25): msg <- _empty_/InfoMacro.reportInfoMacro().(msg) +[5:27..5:31): Expr -> scala/quoted/Expr# +[5:32..5:38): String -> scala/Predef.String# +[5:47..5:53): Quotes -> scala/quoted/Quotes# +[5:56..5:60): Expr -> scala/quoted/Expr# +[5:61..5:65): Unit -> scala/Unit# +[6:11..6:17): quotes -> scala/quoted/Quotes$package.quotes(). +[6:18..6:25): reflect -> scala/quoted/Quotes#reflect. +[6:26..6:32): report -> scala/quoted/Quotes#reflectModule#report. +[9:4..9:10): report -> scala/quoted/Quotes#reflectModule#report. +[9:11..9:15): info -> scala/quoted/Quotes#reflectModule#reportModule#info(). +[9:16..9:17): s -> scala/StringContext#s(). +[9:37..9:40): msg -> _empty_/InfoMacro.reportInfoMacro().(msg) +[9:41..9:53): valueOrAbort -> scala/quoted/Quotes#valueOrAbort(). + +Synthetics: +[3:48..3:69):reportInfoMacro('msg) => *(contextual$1) +[3:64..3:68):'msg => orig()(contextual$1) +[6:11..6:17):quotes => *(x$2) +[9:37..9:53):msg.valueOrAbort => *(StringFromExpr[String]) +[9:41..9:53):valueOrAbort => *[String] +[11:4..11:11):'{ () } => orig(())(x$2) + +expect/InfoMacroTest.scala +-------------------------- + +Summary: +Schema => SemanticDB v4 +Uri => InfoMacroTest.scala +Text => empty +Language => Scala +Symbols => 2 entries +Occurrences => 7 entries +Diagnostics => 2 entries + +Symbols: +_empty_/InfoMacroTest. => final object InfoMacroTest extends Object { self: InfoMacroTest.type => +2 decls } +_empty_/InfoMacroTest.main(). => method main (): Unit + +Occurrences: +[1:7..1:20): InfoMacroTest <- _empty_/InfoMacroTest. +[2:6..2:10): main <- _empty_/InfoMacroTest.main(). +[2:14..2:18): Unit -> scala/Unit# +[3:4..3:13): InfoMacro -> _empty_/InfoMacro. +[3:14..3:24): reportInfo -> _empty_/InfoMacro.reportInfo(). +[4:4..4:13): InfoMacro -> _empty_/InfoMacro. +[4:14..4:24): reportInfo -> _empty_/InfoMacro.reportInfo(). + +Diagnostics: +[3:4..3:55): [info] Info from macro: This is a test info message +[4:4..4:48): [info] Info from macro: Another info message + expect/InstrumentTyper.scala ----------------------------