001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.tree;
020:
021: import java.io.PrintStream;
022: import java.io.PrintWriter;
023:
024: import java.util.ArrayList;
025: import java.util.List;
026:
027: /**
028: * The superclass of exceptions signaled during visitor dispatch.
029: *
030: * @author Robert Grimm
031: * @version $Revision: 1.2 $
032: */
033: public class TraversalException extends RuntimeException {
034:
035: /**
036: * Create a new traversal exception with the specified detail
037: * message.
038: *
039: * @param message The detail message.
040: */
041: public TraversalException(String message) {
042: super (message);
043: }
044:
045: /**
046: * Create a new traversal exception with the specified detail
047: * message and cause.
048: *
049: * @param message The detail message.
050: * @param cause The cause.
051: */
052: public TraversalException(String message, Throwable cause) {
053: super (message, cause);
054: }
055:
056: public Throwable getCause() {
057: Throwable t = super .getCause();
058: return null == t ? t : clean(t);
059: }
060:
061: public void printStackTrace(PrintStream s) {
062: clean(this );
063: super .printStackTrace(s);
064: }
065:
066: public void printStackTrace(PrintWriter s) {
067: clean(this );
068: super .printStackTrace(s);
069: }
070:
071: /**
072: * Clean the specified throwable's stack trace. This method removes
073: * any evidence of dynamic visitor dispatch from stack traces.
074: *
075: * @param t The throwable.
076: * @return The throwable.
077: */
078: private static <T extends Throwable> T clean(T t) {
079: StackTraceElement oldTrace[] = t.getStackTrace();
080:
081: int size = 0;
082: for (StackTraceElement e : oldTrace) {
083: if (isClean(e))
084: size++;
085: }
086:
087: if (oldTrace.length == size) {
088: if (null != t.getCause())
089: clean(t.getCause());
090: return t;
091: }
092:
093: List<StackTraceElement> newTrace = new ArrayList<StackTraceElement>(
094: size);
095: for (StackTraceElement e : oldTrace) {
096: if (isClean(e))
097: newTrace.add(e);
098: }
099: t.setStackTrace(newTrace.toArray(new StackTraceElement[newTrace
100: .size()]));
101:
102: if (null != t.getCause())
103: clean(t.getCause());
104: return t;
105: }
106:
107: /**
108: * Determine whether the specified stack trace element is clean,
109: * i.e., does not refer to {@link Visitor#dispatch(Node)} or Java
110: * reflection.
111: *
112: * @param e The stack trace element.
113: * @return <code>true</code> if the element is clean.
114: */
115: private static boolean isClean(StackTraceElement e) {
116: String klass = e.getClassName();
117: String method = e.getMethodName();
118:
119: return (!((method.equals("dispatch") && klass
120: .equals("xtc.tree.Visitor")) || (method
121: .startsWith("invoke") && (klass
122: .equals("java.lang.reflect.Method") || klass
123: .startsWith("sun.reflect.")))));
124: }
125:
126: }
|