From d344e8a91bdbfedc28527c3fc7d6d243dff9e3e6 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 12 Aug 2022 20:56:42 +0000 Subject: Show equivalent warnings/errors only once (#2673) (#2675) (cherry picked from commit ae76ff4cb303a6646e48dc044be47051b67e7cbb) Co-authored-by: Zachary Yedidia --- core/src/main/scala/chisel3/internal/Error.scala | 41 ++++++++++++++---------- src/test/scala/chiselTests/WarningSpec.scala | 35 ++++++++++++++++++++ 2 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 src/test/scala/chiselTests/WarningSpec.scala diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala index 3b0846eb..98db7109 100644 --- a/core/src/main/scala/chisel3/internal/Error.scala +++ b/core/src/main/scala/chisel3/internal/Error.scala @@ -177,20 +177,31 @@ private[chisel3] object ErrorLog { } private[chisel3] class ErrorLog { + def getLoc(loc: Option[StackTraceElement]): String = { + loc match { + case Some(elt: StackTraceElement) => s"${elt.getFileName}:${elt.getLineNumber}" + case None => "(unknown)" + } + } /** Log an error message */ - def error(m: => String): Unit = - errors += new Error(m, getUserLineNumber) + def error(m: => String): Unit = { + val loc = getUserLineNumber + errors += (((m, getLoc(loc)), new Error(m, loc))) + } /** Log a warning message */ - def warning(m: => String): Unit = - errors += new Warning(m, getUserLineNumber) - - /** Log a warning message without a source locator */ - def warningNoLoc(m: => String): Unit = { - errors += new Warning(m, None) + def warning(m: => String): Unit = { + val loc = getUserLineNumber + errors += (((m, getLoc(loc)), new Warning(m, loc))) } + /** Log a warning message without a source locator. This is used when the + * locator wouldn't be helpful (e.g., due to lazy values). + */ + def warningNoLoc(m: => String): Unit = + errors += (((m, ""), new Warning(m, None))) + /** Emit an informational message */ @deprecated("This method will be removed in 3.5", "3.4") def info(m: String): Unit = @@ -200,11 +211,7 @@ private[chisel3] class ErrorLog { def deprecated(m: => String, location: Option[String]): Unit = { val sourceLoc = location match { case Some(loc) => loc - case None => - getUserLineNumber match { - case Some(elt: StackTraceElement) => s"${elt.getFileName}:${elt.getLineNumber}" - case None => "(unknown)" - } + case None => getLoc(getUserLineNumber) } val thisEntry = (m, sourceLoc) @@ -217,7 +224,7 @@ private[chisel3] class ErrorLog { case ((message, sourceLoc), count) => logger.warn(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message") } - errors.foreach(e => logger.error(e.toString)) + errors.foreach(e => logger.error(e._2.toString)) if (!deprecations.isEmpty) { logger.warn( @@ -233,8 +240,8 @@ private[chisel3] class ErrorLog { logger.warn(s"""${ErrorLog.warnTag} scalacOptions := Seq("-unchecked", "-deprecation")""") } - val allErrors = errors.filter(_.isFatal) - val allWarnings = errors.filter(!_.isFatal) + val allErrors = errors.filter(_._2.isFatal) + val allWarnings = errors.filter(!_._2.isFatal) if (!allWarnings.isEmpty && !allErrors.isEmpty) { logger.warn( @@ -289,7 +296,7 @@ private[chisel3] class ErrorLog { .headOption } - private val errors = ArrayBuffer[LogEntry]() + private val errors = LinkedHashMap[(String, String), LogEntry]() private val deprecations = LinkedHashMap[(String, String), Int]() private val startTime = System.currentTimeMillis diff --git a/src/test/scala/chiselTests/WarningSpec.scala b/src/test/scala/chiselTests/WarningSpec.scala new file mode 100644 index 00000000..bf3830d6 --- /dev/null +++ b/src/test/scala/chiselTests/WarningSpec.scala @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chiselTests + +import chisel3._ +import chisel3.util._ +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} +import chisel3.experimental.ChiselEnum +import chisel3.experimental.EnumType +import chiselTests.ChiselFlatSpec + +class WarningSpec extends ChiselFlatSpec with Utils { + behavior.of("Warnings") + + "Warnings" should "be de-duplicated" in { + object MyEnum extends ChiselEnum { + val e0, e1, e2 = Value + } + + class MyModule extends Module { + val in = IO(Input(UInt(2.W))) + val out1 = IO(Output(MyEnum())) + val out2 = IO(Output(MyEnum())) + def func(out: EnumType): Unit = { + out := MyEnum(in) + } + func(out1) + func(out2) + } + val (log, _) = grabLog(ChiselStage.elaborate(new MyModule)) + def countSubstring(s: String, sub: String) = + s.sliding(sub.length).count(_ == sub) + countSubstring(log, "Casting non-literal UInt") should be(1) + } +} -- cgit v1.2.3