blob: 5e36ba372a9a2e4fc4aa3db827744fe18078116c [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.jjs;
import java.util.ArrayList;
import java.util.List;
/**
* Indicates the compiler encountered an unexpected and unsupported state of
* operation.
*/
public class InternalCompilerException extends RuntimeException {
/**
* Information regarding a node that was being processed when an
* InternalCompilerException was thrown.
*/
public static final class NodeInfo {
static void preload() {
// Initialize this class on static invocation.
}
private final String className;
private final String description;
private final SourceInfo sourceInfo;
NodeInfo(String className, String description, SourceInfo sourceInfo) {
this.className = className;
this.description = description;
this.sourceInfo = sourceInfo;
}
/**
* Returns the name of the Java class of the node.
*/
public String getClassName() {
return className;
}
/**
* Returns a text description of the node; typically toString().
*/
public String getDescription() {
return description;
}
/**
* Returns the node's source info, if available; otherwise <code>null</code>.
*/
public SourceInfo getSourceInfo() {
return sourceInfo;
}
}
/**
* Tracks if there's a pending addNode() to avoid recursion sickness.
*/
private static final ThreadLocal<InternalCompilerException> pendingICE = new ThreadLocal<InternalCompilerException>();
/**
* Force this class to be preloaded. If we don't preload this class, we can
* get into bad behavior if we later try to load this class under out of
* memory or out of stack conditions.
*/
public static void preload() {
// Initialize this class on static invocation.
NodeInfo.preload();
pendingICE.set(pendingICE.get());
}
private final List<NodeInfo> nodeTrace = new ArrayList<NodeInfo>();
/**
* Constructs a new exception with the specified node, message, and cause.
*/
public InternalCompilerException(HasSourceInfo node, String message,
Throwable cause) {
this(message, cause);
addNode(node);
}
/**
* Constructs a new exception with the specified message.
*/
public InternalCompilerException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified message and cause.
*/
public InternalCompilerException(String message, Throwable cause) {
super(message, cause);
}
/**
* Adds a node to the end of the node trace. This is similar to how a stack
* trace works.
*/
public void addNode(HasSourceInfo node) {
InternalCompilerException other = pendingICE.get();
if (other != null) {
// Avoiding recursion sickness: Yet Another ICE must have occurred while
// generating info for a prior ICE. Just bail!
return;
}
String className = null;
String description = null;
SourceInfo sourceInfo = null;
try {
pendingICE.set(this);
className = node.getClass().getName();
sourceInfo = node.getSourceInfo();
description = node.toString();
} catch (Throwable e) {
// ignore any exceptions
if (description == null) {
description = "<source info not available>";
}
} finally {
pendingICE.set(null);
}
addNode(className, description, sourceInfo);
}
/**
* Adds information about a a node to the end of the node trace. This is
* similar to how a stack trace works.
*/
public void addNode(String className, String description,
SourceInfo sourceInfo) {
nodeTrace.add(new NodeInfo(className, description, sourceInfo));
}
/**
* Returns a list of nodes that were being processed when this exception was
* thrown. The list reflects the parent-child relationships of the AST and is
* is in order from children to parents. The first element of the returned
* list is the node that was most specifically being visited when the
* exception was thrown.
*/
public List<NodeInfo> getNodeTrace() {
return nodeTrace;
}
}