scala.tools.nsc.util.StackTracing.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-compiler Show documentation
Show all versions of scala-compiler Show documentation
Compiler for the Scala Programming Language
The newest version!
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools.nsc.util
import collection.mutable, mutable.ListBuffer
import java.lang.System.lineSeparator
private[util] trait StackTracing extends Any {
/** Format a stack trace, returning the prefix consisting of frames that satisfy a given predicate.
*
* The format is similar to the typical case described in the Javadoc
* for [[java.lang.Throwable#printStackTrace()*]].
* If a stack trace is truncated, it will be followed by a line of the form
* `... 3 elided`, by analogy to the lines `... 3 more` which indicate
* shared stack trace segments.
* @param e the exception
* @param p the predicate to select the prefix
*/
def stackTracePrefixString(e: Throwable)(p: StackTraceElement => Boolean): String = {
type TraceRelation = String
val Self = new TraceRelation("")
val CausedBy = new TraceRelation("Caused by: ")
val Suppressed = new TraceRelation("Suppressed: ")
def header(e: Throwable): String = {
def because = e.getCause match { case null => null ; case c => header(c) }
def msg = e.getMessage match { case null => because ; case s => s }
def txt = msg match { case null => "" ; case s => s": $s" }
s"${e.getClass.getName}$txt"
}
val seen = mutable.Set.empty[Throwable]
def unseen(t: Throwable) = {
val interesting = t != null && !seen(t)
if (interesting) seen += t
interesting
}
val lines = ListBuffer.empty[String]
// format the stack trace, skipping the shared trace
def print(e: Throwable, r: TraceRelation, share: Array[StackTraceElement], indents: Int): Unit = if (unseen(e)) {
val trace = e.getStackTrace
val frames = if (share.isEmpty) trace else {
val spare = share.reverseIterator
val trimmed = trace.reverse dropWhile (spare.hasNext && spare.next == _)
trimmed.reverse
}
val prefix = frames.takeWhile(p)
val margin = " " * indents
lines += s"$margin$r${header(e)}"
prefix.foreach(frame => lines += s"$margin at $frame")
val traceFramesLenDiff = trace.length - frames.length
val framesPrefixLenDiff = frames.length - prefix.length
if (traceFramesLenDiff > 0) {
if (framesPrefixLenDiff > 0) lines += s"$margin ... $framesPrefixLenDiff elided and $traceFramesLenDiff more"
else lines += s"$margin ... $traceFramesLenDiff more"
} else if (framesPrefixLenDiff > 0) lines += s"$margin ... $framesPrefixLenDiff elided"
print(e.getCause, CausedBy, trace, indents)
e.getSuppressed.foreach(print(_, Suppressed, frames, indents + 1))
}
print(e, Self, share = Array.empty, indents = 0)
lines.mkString(lineSeparator)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy