misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / flow / ExceptionHandlingFlowContext.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.flow;
12
13 import java.util.ArrayList;
14
15 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
16 import net.sourceforge.phpdt.internal.compiler.ast.TryStatement;
17 import net.sourceforge.phpdt.internal.compiler.codegen.ObjectCache;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
22
23 /**
24  * Reflects the context of code analysis, keeping track of enclosing
25  *      try statements, exception handlers, etc...
26  */
27 public class ExceptionHandlingFlowContext extends FlowContext {
28         
29         ReferenceBinding[] handledExceptions;
30         
31         public final static int BitCacheSize = 32; // 32 bits per int
32         int[] isReached;
33         int[] isNeeded;
34         UnconditionalFlowInfo[] initsOnExceptions;
35         ObjectCache indexes = new ObjectCache();
36         boolean isMethodContext;
37
38         public UnconditionalFlowInfo initsOnReturn;
39
40         // for dealing with anonymous constructor thrown exceptions
41         public ArrayList extendedExceptions;
42         
43         public ExceptionHandlingFlowContext(
44                 FlowContext parent,
45                 AstNode associatedNode,
46                 ReferenceBinding[] handledExceptions,
47                 BlockScope scope,
48                 UnconditionalFlowInfo flowInfo) {
49
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
59                         boolean isUnchecked =
60                                 (scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
61                         int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
62                         if (isUnchecked) {
63                                 isReached[cacheIndex] |= bitMask;
64                                 this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
65                         } else {
66                                 this.initsOnExceptions[i] = FlowInfo.DeadEnd;
67                         }
68                 }
69                 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize);
70                 this.initsOnReturn = FlowInfo.DeadEnd;  
71         }
72
73         public void complainIfUnusedExceptionHandlers(
74                 AstNode[] exceptionHandlers,
75                 BlockScope scope,
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]);
86                         } else {
87                                 if ((isNeeded[cacheIndex] & bitMask) == 0) {
88                                         scope.problemReporter().maskedExceptionHandler(
89                                                 handledExceptions[index],
90                                                 exceptionHandlers[index]);
91                                 }
92                         }
93                 }
94                 // will optimized out unnecessary catch block during code gen
95                 tryStatement.preserveExceptionHandler = isNeeded;
96         }
97
98         public String individualToString() {
99                 
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$
109                                 } else {
110                                         buffer.append("-reached"); //$NON-NLS-1$
111                                 }
112                         } else {
113                                 buffer.append("-not reached"); //$NON-NLS-1$
114                         }
115                         buffer.append('-').append(initsOnExceptions[i].toString()).append(']');
116                 }
117                 return buffer.toString();
118         }
119
120         public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
121                 
122                 int index;
123                 if ((index = indexes.get(exceptionType)) < 0) {
124                         return FlowInfo.DeadEnd;
125                 }
126                 return initsOnExceptions[index];
127         }
128
129         public void recordHandlingException(
130                 ReferenceBinding exceptionType,
131                 UnconditionalFlowInfo flowInfo,
132                 TypeBinding raisedException,
133                 AstNode invocationSite,
134                 boolean wasAlreadyDefinitelyCaught) {
135                         
136                 int index = indexes.get(exceptionType);
137                 // if already flagged as being reached (unchecked exception handler)
138                 int cacheIndex = index / BitCacheSize;
139                 int bitMask = 1 << (index % BitCacheSize);
140                 if (!wasAlreadyDefinitelyCaught) {
141                         this.isNeeded[cacheIndex] |= bitMask;
142                 }
143                 this.isReached[cacheIndex] |= bitMask;
144                 initsOnExceptions[index] =
145                         initsOnExceptions[index] == FlowInfo.DeadEnd
146                                 ? flowInfo.copy().unconditionalInits()
147                                 : initsOnExceptions[index].mergedWith(flowInfo);
148         }
149         
150         public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
151                 
152                 // record initializations which were performed at the return point
153                 initsOnReturn = initsOnReturn.mergedWith(flowInfo);
154         }
155         
156         /*
157          * Compute a merged list of unhandled exception types (keeping only the most generic ones).
158          * This is necessary to add synthetic thrown exceptions for anonymous type constructors (JLS 8.6).
159          */
160         public void mergeUnhandledException(TypeBinding newException){
161                 
162                 if (this.extendedExceptions == null){
163                         this.extendedExceptions = new ArrayList(5);
164                         for (int i = 0; i < this.handledExceptions.length; i++){
165                                 this.extendedExceptions.add(this.handledExceptions[i]);
166                         }
167                 }
168                 
169                 boolean isRedundant = false;
170                 
171                 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){
172                         switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){
173                                 case MoreGeneric :
174                                         this.extendedExceptions.remove(i);
175                                         break;
176                                 case EqualOrMoreSpecific :
177                                         isRedundant = true;
178                                         break;
179                                 case NotRelated :
180                                         break;
181                         }
182                 }
183                 if (!isRedundant){
184                         this.extendedExceptions.add(newException);
185                 }
186         }
187 }