+++ /dev/null
-/*******************************************************************************
- * 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);
- }
- }
-}