Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't ... top of stack trace if it isn't actually trimmed #4142

Merged
merged 1 commit into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions core/src/main/scala/chisel3/internal/Error.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,32 +54,32 @@ object ExceptionHelpers {
packageTrimlist.contains(packageName)
}

// Step 1: Remove elements from the top in the package trimlist
val trimStackTrace =
((a: Array[StackTraceElement]) => a.dropWhile(inTrimlist))
// Step 2: Optionally remove elements from the bottom until the anchor
.andThen(_.reverse)
.andThen(a =>
anchor match {
case Some(b) => a.dropWhile(ste => !ste.getClassName.startsWith(b))
case None => a
}
)
// Step 3: Remove elements from the bottom in the package trimlist
.andThen(_.dropWhile(inTrimlist))
// Step 4: Reverse back to the original order
.andThen(_.reverse.toArray)
(a: Array[StackTraceElement]) => {
// Step 1: Remove elements from the top in the package trimlist
// Only include ellipsis at top if something is dropped from top
val droppedFromTop = inTrimlist(a.head)
val trimmed =
a.dropWhile(inTrimlist)
// Step 2: Optionally remove elements from the bottom until the anchor
.reverse
.dropWhile(ste => anchor.map(b => !ste.getClassName.startsWith(b)).getOrElse(false))
// Step 3: Remove elements from the bottom in the package trimlist
.dropWhile(inTrimlist)
// Step 4: Reverse back to the original order
.reverse
.toArray
// Step 5: Add ellipsis stack trace elements and "--full-stacktrace" info
.andThen(a =>
ellipsis() +:
a :+
val withEllipses =
Option.when(droppedFromTop)(ellipsis()) ++:
trimmed :+
ellipsis() :+
ellipsis(
Some("Stack trace trimmed to user code only. Rerun with --full-stacktrace to see the full stack trace")
)
)
// Step 5: Mutate the stack trace in this exception
.andThen(throwable.setStackTrace(_))
// Step 6: Mutate the stack trace in this exception
throwable.setStackTrace(withEllipses)
}

val stackTrace = throwable.getStackTrace
if (stackTrace.nonEmpty) {
Expand Down
80 changes: 67 additions & 13 deletions src/test/scala/circtTests/stage/ChiselStageSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,12 @@ object ChiselStageSpec {
})
}

class UserAssertionModule extends RawModule {
assert(false, "User had an assertion")
}

class UserExceptionModule extends RawModule {
assert(false, "User threw an exception")
throw new Exception("User threw an exception")
}

class UserExceptionNoStackTrace extends RawModule {
Expand Down Expand Up @@ -410,38 +414,63 @@ class ChiselStageSpec extends AnyFunSpec with Matchers with chiselTests.Utils {
(new ChiselStage)
.execute(
Array("--target", "chirrtl"),
Seq(ChiselGeneratorAnnotation(() => new ChiselStageSpec.UserExceptionModule))
Seq(ChiselGeneratorAnnotation(() => new ChiselStageSpec.UserAssertionModule))
)
}

info(s""" - Exception was a ${exception.getClass.getName}""")

val message = exception.getMessage
info("The exception includes the user's message")
message should include("User threw an exception")
message should include("User had an assertion")

val stackTrace = exception.getStackTrace.mkString("\n")
info("The stack trace is trimmed")
(stackTrace should not).include("java")
val stackTrace = exception.getStackTrace
info("The stack trace is trimmed at the top")
stackTrace.head.toString should include("...")

info("The stack trace is trimmed at the bottom")
stackTrace.last.toString should include("...")

info("The stack trace include information about running --full-stacktrace")
stackTrace should include("--full-stacktrace")
stackTrace.last.toString should include("--full-stacktrace")
}

it("should NOT truncate the top of the stack trace if it points to user code") {
info("The user's Exception was thrown")
val exception = intercept[Exception] {
(new ChiselStage)
.execute(
Array("--target", "chirrtl"),
Seq(ChiselGeneratorAnnotation(() => new ChiselStageSpec.UserExceptionModule))
)
}

val message = exception.getMessage
info("The exception includes the user's message")
message should include("User threw an exception")

val stackTrace = exception.getStackTrace
info("The stack trace is NOT trimmed at the top")
stackTrace.head.toString shouldNot include("...")

info("The stack trace is trimmed at the bottom")
stackTrace.last.toString should include("...")
}

it("""should not truncate a user exception with "--full-stacktrace"""") {
info("The user's java.lang.AssertionError was thrown")
val exception = intercept[java.lang.AssertionError] {
(new ChiselStage).execute(
Array("--target", "chirrtl", "--full-stacktrace"),
Seq(ChiselGeneratorAnnotation(() => new ChiselStageSpec.UserExceptionModule))
Seq(ChiselGeneratorAnnotation(() => new ChiselStageSpec.UserAssertionModule))
)
}

info(s""" - Exception was a ${exception.getClass.getName}""")

val message = exception.getMessage
info("The exception includes the user's message")
message should include("User threw an exception")
message should include("User had an assertion")

info("The stack trace is not trimmed")
exception.getStackTrace.mkString("\n") should include("java")
Expand Down Expand Up @@ -527,7 +556,7 @@ class ChiselStageSpec extends AnyFunSpec with Matchers with chiselTests.Utils {
val lines = stdout.split("\n")
// Fuzzy includes aren't ideal but there is ANSI color in these strings that is hard to match
lines(0) should include(
"src/test/scala/circtTests/stage/ChiselStageSpec.scala 91:9: Negative shift amounts are illegal (got -1)"
"src/test/scala/circtTests/stage/ChiselStageSpec.scala 95:9: Negative shift amounts are illegal (got -1)"
)
lines(1) should include(" 3.U >> -1")
lines(2) should include(" ^")
Expand All @@ -548,7 +577,7 @@ class ChiselStageSpec extends AnyFunSpec with Matchers with chiselTests.Utils {
// Fuzzy includes aren't ideal but there is ANSI color in these strings that is hard to match
lines.size should equal(2)
lines(0) should include(
"src/test/scala/circtTests/stage/ChiselStageSpec.scala 91:9: Negative shift amounts are illegal (got -1)"
"src/test/scala/circtTests/stage/ChiselStageSpec.scala 95:9: Negative shift amounts are illegal (got -1)"
)
(lines(1) should not).include("3.U >> -1")
}
Expand Down Expand Up @@ -1187,15 +1216,40 @@ class ChiselStageSpec extends AnyFunSpec with Matchers with chiselTests.Utils {
it("should truncate a user exception") {
info("The user's java.lang.AssertionError was thrown")
val exception = intercept[java.lang.AssertionError] {
ChiselStage.emitCHIRRTL(new ChiselStageSpec.UserAssertionModule)
}

val message = exception.getMessage
info("The exception includes the user's message")
message should include("User had an assertion")

val stackTrace = exception.getStackTrace
info("The stack trace is trimmed at the top")
stackTrace.head.toString should include("...")

info("The stack trace is trimmed at the bottom")
stackTrace.last.toString should include("...")

info("The stack trace include information about running --full-stacktrace")
stackTrace.last.toString should include("--full-stacktrace")
}

it("should NOT truncate the top of the stack trace if it points to user code") {
info("The user's Exception was thrown")
val exception = intercept[Exception] {
ChiselStage.emitCHIRRTL(new ChiselStageSpec.UserExceptionModule)
}

val message = exception.getMessage
info("The exception includes the user's message")
message should include("User threw an exception")

info("The stack trace is trimmed")
(exception.getStackTrace.mkString("\n") should not).include("java")
val stackTrace = exception.getStackTrace
info("The stack trace is NOT trimmed at the top")
stackTrace.head.toString shouldNot include("...")

info("The stack trace is trimmed at the bottom")
stackTrace.last.toString should include("...")
}

it("should NOT add a stack trace to an exception with no stack trace") {
Expand Down