package org.eclipse.jdt.internal.compiler.flow;

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.codegen.*;

/**
 * Reflects the context of code analysis, keeping track of enclosing
 *	try statements, exception handlers, etc...
 */
public class ExceptionHandlingFlowContext extends FlowContext {
	ReferenceBinding[] handledExceptions;

	public final static int BitCacheSize = 32; // 32 bits per int
	int[] isReached;
	int[] isNeeded;
	UnconditionalFlowInfo[] initsOnExceptions;
	ObjectCache indexes = new ObjectCache();
	boolean isMethodContext;
public ExceptionHandlingFlowContext(
	FlowContext parent, 
	AstNode associatedNode, 
	ReferenceBinding[] handledExceptions, 
	BlockScope scope, 
	UnconditionalFlowInfo flowInfo) {

	super(parent, associatedNode);
	isMethodContext = scope == scope.methodScope();
/*	
	// for a method, append the unchecked exceptions to the handled exceptions collection

	if (scope.methodScope() == scope) {
		int length;
		System.arraycopy(
			handledExceptions, 
			0, 
			(handledExceptions = 
				new ReferenceBinding[(length = handledExceptions.length) + 2]), 
			0, 
			length); 
		handledExceptions[length] = scope.getJavaLangRuntimeException();
		handledExceptions[length + 1] = scope.getJavaLangError();
	}
*/	
	this.handledExceptions = handledExceptions;
	int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1;
	isReached = new int[cacheSize]; // none is reached by default
	isNeeded = new int[cacheSize]; // none is needed by default
	initsOnExceptions = new UnconditionalFlowInfo[count];
	for (int i = 0; i < count; i++) {
		indexes.put(handledExceptions[i], i); // key type  -> value index
		boolean isUnchecked = 
			(scope.compareUncheckedException(handledExceptions[i]) != NotRelated); 
		int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
		if (isUnchecked) {
			isReached[cacheIndex] |= bitMask;
			initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
		} else {
			initsOnExceptions[i] = FlowInfo.DeadEnd;
		}
	}
	System.arraycopy(isReached, 0, isNeeded, 0, cacheSize);
}
public void complainIfUnusedExceptionHandlers(AstNode[] exceptionHandlers, BlockScope scope, TryStatement tryStatement) {

	// report errors for unreachable exception handlers

	for (int i = 0, count = handledExceptions.length; i < count; i++) {
		int index = indexes.get(handledExceptions[i]);
		int cacheIndex = index / BitCacheSize;
		int bitMask	= 1 << (index % BitCacheSize);
		if ((isReached[cacheIndex] & bitMask) == 0) {
			scope.problemReporter().unreachableExceptionHandler(
				handledExceptions[index], 
				exceptionHandlers[index]); 
		} else {
			if ((isNeeded[cacheIndex] & bitMask) == 0) {
				scope.problemReporter().maskedExceptionHandler(
					handledExceptions[index], 
					exceptionHandlers[index]); 
			}
		}
	}
	// will optimized out unnecessary catch block during code gen
	tryStatement.preserveExceptionHandler = isNeeded;
}
public String individualToString() {
	StringBuffer buffer = new StringBuffer("Exception flow context"/*nonNLS*/);
	int length = handledExceptions.length;
	for (int i = 0; i < length; i++) {
		int cacheIndex = i / BitCacheSize;
		int bitMask = 1 << (i % BitCacheSize);		
		buffer.append('[').append(handledExceptions[i].readableName());
		if ((isReached[cacheIndex] & bitMask) != 0) {
			if ((isNeeded[cacheIndex] & bitMask) == 0) {
				buffer.append("-masked"/*nonNLS*/);
			} else {
				buffer.append("-reached"/*nonNLS*/);
			}
		} else {
			buffer.append("-not reached"/*nonNLS*/);
		}
		buffer.append('-').append(initsOnExceptions[i].toString()).append(']');
	}
	return buffer.toString();
}
public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {

	int index;
	if ((index = indexes.get(exceptionType)) < 0) {
		return FlowInfo.DeadEnd;
	}
	return initsOnExceptions[index];
}
public void recordHandlingException(ReferenceBinding exceptionType, UnconditionalFlowInfo flowInfo, TypeBinding raisedException, AstNode invocationSite, boolean wasAlreadyDefinitelyCaught) {
		
	int index = indexes.get(exceptionType);
	// if already flagged as being reached (unchecked exception handler)
	int cacheIndex = index / BitCacheSize;
	int bitMask = 1 << (index % BitCacheSize);
	if (!wasAlreadyDefinitelyCaught) {
		this.isNeeded[cacheIndex] |= bitMask;
	}
	this.isReached[cacheIndex] |= bitMask;
	initsOnExceptions[index] = 
		initsOnExceptions[index] == FlowInfo.DeadEnd
			? flowInfo.copy().unconditionalInits()
			: initsOnExceptions[index].mergedWith(flowInfo); 
}
}
