removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / flow / ExceptionHandlingFlowContext.java
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 (file)
index 0000000..4862742
--- /dev/null
@@ -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);
+               }
+       }
+}