X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fflow%2FExceptionHandlingFlowContext.java;fp=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fflow%2FExceptionHandlingFlowContext.java;h=486274250438ffb46263762b9d4af468f8a77b7e;hb=040fa5af2cd00017cf3575950cdaade34a6d7f6c;hp=0000000000000000000000000000000000000000;hpb=a580fb8376d315d05e4d6bfdff9ff1101a151cd6;p=org.ibex.tool.git diff --git a/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java new file mode 100644 index 0000000..4862742 --- /dev/null +++ b/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.flow; + +import java.util.ArrayList; + +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.TryStatement; +import org.eclipse.jdt.internal.compiler.codegen.ObjectCache; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; + +/** + * Reflects the context of code analysis, keeping track of enclosing + * try statements, exception handlers, etc... + */ +public class ExceptionHandlingFlowContext extends FlowContext { + + public 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 UnconditionalFlowInfo initsOnReturn; + + // for dealing with anonymous constructor thrown exceptions + public ArrayList extendedExceptions; + + public ExceptionHandlingFlowContext( + FlowContext parent, + ASTNode associatedNode, + ReferenceBinding[] handledExceptions, + BlockScope scope, + UnconditionalFlowInfo flowInfo) { + + super(parent, associatedNode); + isMethodContext = scope == scope.methodScope(); + this.handledExceptions = handledExceptions; + int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1; + this.isReached = new int[cacheSize]; // none is reached by default + this.isNeeded = new int[cacheSize]; // none is needed by default + this.initsOnExceptions = new UnconditionalFlowInfo[count]; + for (int i = 0; i < count; i++) { + this.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; + this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits(); + } else { + this.initsOnExceptions[i] = FlowInfo.DEAD_END; + } + } + System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize); + this.initsOnReturn = FlowInfo.DEAD_END; + } + + public void complainIfUnusedExceptionHandlers(AbstractMethodDeclaration method) { + MethodScope scope = method.scope; + // can optionally skip overriding methods + if ((method.binding.modifiers & (CompilerModifiers.AccOverriding | CompilerModifiers.AccImplementing)) != 0 + && !scope.environment().options.reportUnusedDeclaredThrownExceptionWhenOverriding) { + return; + } + + // 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().unusedDeclaredThrownException( + handledExceptions[index], + method, + method.thrownExceptions[index]); + } + } + } + + public void complainIfUnusedExceptionHandlers( + 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().unreachableCatchBlock( + handledExceptions[index], + tryStatement.catchArguments[index].type); + } else { + if ((isNeeded[cacheIndex] & bitMask) == 0) { + scope.problemReporter().hiddenCatchBlock( + handledExceptions[index], + tryStatement.catchArguments[index].type); + } + } + } + } + + public String individualToString() { + + StringBuffer buffer = new StringBuffer("Exception flow context"); //$NON-NLS-1$ + 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"); //$NON-NLS-1$ + } else { + buffer.append("-reached"); //$NON-NLS-1$ + } + } else { + buffer.append("-not reached"); //$NON-NLS-1$ + } + buffer.append('-').append(initsOnExceptions[i].toString()).append(']'); + } + buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$ + return buffer.toString(); + } + + public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) { + + int index; + if ((index = indexes.get(exceptionType)) < 0) { + return FlowInfo.DEAD_END; + } + return initsOnExceptions[index]; + } + + public UnconditionalFlowInfo initsOnReturn(){ + return this.initsOnReturn; + } + + 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.DEAD_END + ? flowInfo.copy().unconditionalInits() + : initsOnExceptions[index].mergedWith(flowInfo.copy().unconditionalInits()); + } + + public void recordReturnFrom(FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return; + if (initsOnReturn == FlowInfo.DEAD_END) { + initsOnReturn = flowInfo.copy().unconditionalInits(); + } else { + initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits()); + } + } + + /* + * Compute a merged list of unhandled exception types (keeping only the most generic ones). + * This is necessary to add synthetic thrown exceptions for anonymous type constructors (JLS 8.6). + */ + public void mergeUnhandledException(TypeBinding newException){ + + if (this.extendedExceptions == null){ + this.extendedExceptions = new ArrayList(5); + for (int i = 0; i < this.handledExceptions.length; i++){ + this.extendedExceptions.add(this.handledExceptions[i]); + } + } + + boolean isRedundant = false; + + for(int i = this.extendedExceptions.size()-1; i >= 0; i--){ + switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){ + case MoreGeneric : + this.extendedExceptions.remove(i); + break; + case EqualOrMoreSpecific : + isRedundant = true; + break; + case NotRelated : + break; + } + } + if (!isRedundant){ + this.extendedExceptions.add(newException); + } + } +}