/* * xtc - The eXTensible Compiler * Copyright (C) 2007 Robert Grimm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.tree; import java.io.PrintStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** * The superclass of exceptions signaled during visitor dispatch. * * @author Robert Grimm * @version $Revision: 1.2 $ */ public class TraversalException extends RuntimeException { /** * Create a new traversal exception with the specified detail * message. * * @param message The detail message. */ public TraversalException(String message) { super(message); } /** * Create a new traversal exception with the specified detail * message and cause. * * @param message The detail message. * @param cause The cause. */ public TraversalException(String message, Throwable cause) { super(message, cause); } public Throwable getCause() { Throwable t = super.getCause(); return null == t ? t : clean(t); } public void printStackTrace(PrintStream s) { clean(this); super.printStackTrace(s); } public void printStackTrace(PrintWriter s) { clean(this); super.printStackTrace(s); } /** * Clean the specified throwable's stack trace. This method removes * any evidence of dynamic visitor dispatch from stack traces. * * @param t The throwable. * @return The throwable. */ private static <T extends Throwable> T clean(T t) { StackTraceElement oldTrace[] = t.getStackTrace(); int size = 0; for (StackTraceElement e : oldTrace) { if (isClean(e)) size++; } if (oldTrace.length == size) { if (null != t.getCause()) clean(t.getCause()); return t; } List<StackTraceElement> newTrace = new ArrayList<StackTraceElement>(size); for (StackTraceElement e : oldTrace) { if (isClean(e)) newTrace.add(e); } t.setStackTrace(newTrace.toArray(new StackTraceElement[newTrace.size()])); if (null != t.getCause()) clean(t.getCause()); return t; } /** * Determine whether the specified stack trace element is clean, * i.e., does not refer to {@link Visitor#dispatch(Node)} or Java * reflection. * * @param e The stack trace element. * @return <code>true</code> if the element is clean. */ private static boolean isClean(StackTraceElement e) { String klass = e.getClassName(); String method = e.getMethodName(); return (! ((method.equals("dispatch") && klass.equals("xtc.tree.Visitor")) || (method.startsWith("invoke") && (klass.equals("java.lang.reflect.Method") || klass.startsWith("sun.reflect."))))); } }