5a2b0729f281bcc0496f23789b495fdb5b9b4ae5
[phpeclipse.git] /
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
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.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
22 /**
23  * Reflects the context of code analysis, keeping track of enclosing
24  *      try statements, exception handlers, etc...
25  */
26 public class ExceptionHandlingFlowContext extends FlowContext {
27         
28         public ReferenceBinding[] handledExceptions;
29         
30         public final static int BitCacheSize = 32; // 32 bits per int
31         int[] isReached;
32         int[] isNeeded;
33         UnconditionalFlowInfo[] initsOnExceptions;
34         ObjectCache indexes = new ObjectCache();
35         boolean isMethodContext;
36
37         public UnconditionalFlowInfo initsOnReturn;
38
39         // for dealing with anonymous constructor thrown exceptions
40         public ArrayList extendedExceptions;
41         
42         public ExceptionHandlingFlowContext(
43                 FlowContext parent,
44                 ASTNode associatedNode,
45                 ReferenceBinding[] handledExceptions,
46                 BlockScope scope,
47                 UnconditionalFlowInfo flowInfo) {
48
49                 super(parent, associatedNode);
50                 isMethodContext = scope == scope.methodScope();
51                 this.handledExceptions = handledExceptions;
52                 int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1;
53                 this.isReached = new int[cacheSize]; // none is reached by default
54                 this.isNeeded = new int[cacheSize]; // none is needed by default
55                 this.initsOnExceptions = new UnconditionalFlowInfo[count];
56                 for (int i = 0; i < count; i++) {
57                         this.indexes.put(handledExceptions[i], i); // key type  -> value index
58                         boolean isUnchecked =
59                                 (scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
60                         int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
61                         if (isUnchecked) {
62                                 isReached[cacheIndex] |= bitMask;
63                                 this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
64                         } else {
65                                 this.initsOnExceptions[i] = FlowInfo.DEAD_END;
66                         }
67                 }
68                 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize);
69                 this.initsOnReturn = FlowInfo.DEAD_END; 
70         }
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                 buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$
118                 return buffer.toString();
119         }
120
121         public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
122                 
123                 int index;
124                 if ((index = indexes.get(exceptionType)) < 0) {
125                         return FlowInfo.DEAD_END;
126                 }
127                 return initsOnExceptions[index];
128         }
129
130         public UnconditionalFlowInfo initsOnReturn(){
131                 return this.initsOnReturn;
132         }
133         
134         public void recordHandlingException(
135                 ReferenceBinding exceptionType,
136                 UnconditionalFlowInfo flowInfo,
137                 TypeBinding raisedException,
138                 ASTNode invocationSite,
139                 boolean wasAlreadyDefinitelyCaught) {
140                         
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;
147                 }
148                 this.isReached[cacheIndex] |= bitMask;
149                 
150                 initsOnExceptions[index] =
151                         initsOnExceptions[index] == FlowInfo.DEAD_END
152                                 ? flowInfo.copy().unconditionalInits()
153                                 : initsOnExceptions[index].mergedWith(flowInfo);
154         }
155         
156         public void recordReturnFrom(FlowInfo flowInfo) {
157
158                 if (!flowInfo.isReachable()) return; 
159                 if (initsOnReturn == FlowInfo.DEAD_END) {
160                         initsOnReturn = flowInfo.copy().unconditionalInits();
161                 } else {
162                         initsOnReturn = initsOnReturn.mergedWith(flowInfo.unconditionalInits());
163                 }
164         }
165         
166         /*
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).
169          */
170         public void mergeUnhandledException(TypeBinding newException){
171                 
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]);
176                         }
177                 }
178                 
179                 boolean isRedundant = false;
180                 
181                 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){
182                         switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){
183                                 case MoreGeneric :
184                                         this.extendedExceptions.remove(i);
185                                         break;
186                                 case EqualOrMoreSpecific :
187                                         isRedundant = true;
188                                         break;
189                                 case NotRelated :
190                                         break;
191                         }
192                 }
193                 if (!isRedundant){
194                         this.extendedExceptions.add(newException);
195                 }
196         }
197 }