1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2003 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.flow;
 
  13 import java.util.ArrayList;
 
  15 import net.sourceforge.phpdt.internal.compiler.codegen.ObjectCache;
 
  16 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
 
  17 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
 
  18 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
 
  19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
 
  20 import net.sourceforge.phpeclipse.internal.compiler.ast.AstNode;
 
  21 import net.sourceforge.phpeclipse.internal.compiler.ast.TryStatement;
 
  24  * Reflects the context of code analysis, keeping track of enclosing
 
  25  *      try statements, exception handlers, etc...
 
  27 public class ExceptionHandlingFlowContext extends FlowContext {
 
  29         public ReferenceBinding[] handledExceptions;
 
  31         public final static int BitCacheSize = 32; // 32 bits per int
 
  34         UnconditionalFlowInfo[] initsOnExceptions;
 
  35         ObjectCache indexes = new ObjectCache();
 
  36         boolean isMethodContext;
 
  38         public UnconditionalFlowInfo initsOnReturn;
 
  40         // for dealing with anonymous constructor thrown exceptions
 
  41         public ArrayList extendedExceptions;
 
  43         public ExceptionHandlingFlowContext(
 
  45                 AstNode associatedNode,
 
  46                 ReferenceBinding[] handledExceptions,
 
  48                 UnconditionalFlowInfo flowInfo) {
 
  50                 super(parent, associatedNode);
 
  51                 isMethodContext = scope == scope.methodScope();
 
  52                 this.handledExceptions = handledExceptions;
 
  53                 int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1;
 
  54                 this.isReached = new int[cacheSize]; // none is reached by default
 
  55                 this.isNeeded = new int[cacheSize]; // none is needed by default
 
  56                 this.initsOnExceptions = new UnconditionalFlowInfo[count];
 
  57                 for (int i = 0; i < count; i++) {
 
  58                         this.indexes.put(handledExceptions[i], i); // key type  -> value index
 
  60                                 (scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
 
  61                         int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
 
  63                                 isReached[cacheIndex] |= bitMask;
 
  64                                 this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
 
  66                                 this.initsOnExceptions[i] = FlowInfo.DEAD_END;
 
  69                 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize);
 
  70                 this.initsOnReturn = FlowInfo.DEAD_END; 
 
  73         public void complainIfUnusedExceptionHandlers(
 
  74                 AstNode[] exceptionHandlers,
 
  76                 TryStatement tryStatement) {
 
  77                 // report errors for unreachable exception handlers
 
  78                 for (int i = 0, count = handledExceptions.length; i < count; i++) {
 
  79                         int index = indexes.get(handledExceptions[i]);
 
  80                         int cacheIndex = index / BitCacheSize;
 
  81                         int bitMask = 1 << (index % BitCacheSize);
 
  82                         if ((isReached[cacheIndex] & bitMask) == 0) {
 
  83                                 scope.problemReporter().unreachableExceptionHandler(
 
  84                                         handledExceptions[index],
 
  85                                         exceptionHandlers[index]);
 
  87                                 if ((isNeeded[cacheIndex] & bitMask) == 0) {
 
  88                                         scope.problemReporter().maskedExceptionHandler(
 
  89                                                 handledExceptions[index],
 
  90                                                 exceptionHandlers[index]);
 
  94                 // will optimized out unnecessary catch block during code gen
 
  95                 tryStatement.preserveExceptionHandler = isNeeded;
 
  98         public String individualToString() {
 
 100                 StringBuffer buffer = new StringBuffer("Exception flow context"); //$NON-NLS-1$
 
 101                 int length = handledExceptions.length;
 
 102                 for (int i = 0; i < length; i++) {
 
 103                         int cacheIndex = i / BitCacheSize;
 
 104                         int bitMask = 1 << (i % BitCacheSize);
 
 105                         buffer.append('[').append(handledExceptions[i].readableName());
 
 106                         if ((isReached[cacheIndex] & bitMask) != 0) {
 
 107                                 if ((isNeeded[cacheIndex] & bitMask) == 0) {
 
 108                                         buffer.append("-masked"); //$NON-NLS-1$
 
 110                                         buffer.append("-reached"); //$NON-NLS-1$
 
 113                                 buffer.append("-not reached"); //$NON-NLS-1$
 
 115                         buffer.append('-').append(initsOnExceptions[i].toString()).append(']');
 
 117                 buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$
 
 118                 return buffer.toString();
 
 121         public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
 
 124                 if ((index = indexes.get(exceptionType)) < 0) {
 
 125                         return FlowInfo.DEAD_END;
 
 127                 return initsOnExceptions[index];
 
 130         public UnconditionalFlowInfo initsOnReturn(){
 
 131                 return this.initsOnReturn;
 
 134         public void recordHandlingException(
 
 135                 ReferenceBinding exceptionType,
 
 136                 UnconditionalFlowInfo flowInfo,
 
 137                 TypeBinding raisedException,
 
 138                 AstNode invocationSite,
 
 139                 boolean wasAlreadyDefinitelyCaught) {
 
 141                 int index = indexes.get(exceptionType);
 
 142                 // if already flagged as being reached (unchecked exception handler)
 
 143                 int cacheIndex = index / BitCacheSize;
 
 144                 int bitMask = 1 << (index % BitCacheSize);
 
 145                 if (!wasAlreadyDefinitelyCaught) {
 
 146                         this.isNeeded[cacheIndex] |= bitMask;
 
 148                 this.isReached[cacheIndex] |= bitMask;
 
 150                 initsOnExceptions[index] =
 
 151                         initsOnExceptions[index] == FlowInfo.DEAD_END
 
 152                                 ? flowInfo.copy().unconditionalInits()
 
 153                                 : initsOnExceptions[index].mergedWith(flowInfo);
 
 156         public void recordReturnFrom(FlowInfo flowInfo) {
 
 158                 if (!flowInfo.isReachable()) return; 
 
 159                 if (initsOnReturn == FlowInfo.DEAD_END) {
 
 160                         initsOnReturn = flowInfo.copy().unconditionalInits();
 
 162                         initsOnReturn = initsOnReturn.mergedWith(flowInfo.unconditionalInits());
 
 167          * Compute a merged list of unhandled exception types (keeping only the most generic ones).
 
 168          * This is necessary to add synthetic thrown exceptions for anonymous type constructors (JLS 8.6).
 
 170         public void mergeUnhandledException(TypeBinding newException){
 
 172                 if (this.extendedExceptions == null){
 
 173                         this.extendedExceptions = new ArrayList(5);
 
 174                         for (int i = 0; i < this.handledExceptions.length; i++){
 
 175                                 this.extendedExceptions.add(this.handledExceptions[i]);
 
 179                 boolean isRedundant = false;
 
 181                 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){
 
 182                         switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){
 
 184                                         this.extendedExceptions.remove(i);
 
 186                                 case EqualOrMoreSpecific :
 
 194                         this.extendedExceptions.add(newException);