Makefile fixup
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / flow / ExceptionHandlingFlowContext.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.flow;
12
13 import java.util.ArrayList;
14
15 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
16 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
17 import org.eclipse.jdt.internal.compiler.ast.TryStatement;
18 import org.eclipse.jdt.internal.compiler.codegen.ObjectCache;
19 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
20 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
21 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
22 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
23 import org.eclipse.jdt.internal.compiler.lookup.Scope;
24 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
25
26 /**
27  * Reflects the context of code analysis, keeping track of enclosing
28  *      try statements, exception handlers, etc...
29  */
30 public class ExceptionHandlingFlowContext extends FlowContext {
31         
32         public ReferenceBinding[] handledExceptions;
33         
34         public final static int BitCacheSize = 32; // 32 bits per int
35         int[] isReached;
36         int[] isNeeded;
37         UnconditionalFlowInfo[] initsOnExceptions;
38         ObjectCache indexes = new ObjectCache();
39         boolean isMethodContext;
40
41         public UnconditionalFlowInfo initsOnReturn;
42
43         // for dealing with anonymous constructor thrown exceptions
44         public ArrayList extendedExceptions;
45         
46         public ExceptionHandlingFlowContext(
47                 FlowContext parent,
48                 ASTNode associatedNode,
49                 ReferenceBinding[] handledExceptions,
50                 BlockScope scope,
51                 UnconditionalFlowInfo flowInfo) {
52
53                 super(parent, associatedNode);
54                 isMethodContext = scope == scope.methodScope();
55                 this.handledExceptions = handledExceptions;
56                 int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1;
57                 this.isReached = new int[cacheSize]; // none is reached by default
58                 this.isNeeded = new int[cacheSize]; // none is needed by default
59                 this.initsOnExceptions = new UnconditionalFlowInfo[count];
60                 for (int i = 0; i < count; i++) {
61                         this.indexes.put(handledExceptions[i], i); // key type  -> value index
62                         boolean isUnchecked =
63                                 (scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
64                         int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
65                         if (isUnchecked) {
66                                 isReached[cacheIndex] |= bitMask;
67                                 this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
68                         } else {
69                                 this.initsOnExceptions[i] = FlowInfo.DEAD_END;
70                         }
71                 }
72                 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize);
73                 this.initsOnReturn = FlowInfo.DEAD_END; 
74         }
75
76         public void complainIfUnusedExceptionHandlers(AbstractMethodDeclaration method) {
77                 MethodScope scope = method.scope;
78                 // can optionally skip overriding methods
79                 if ((method.binding.modifiers & (CompilerModifiers.AccOverriding | CompilerModifiers.AccImplementing)) != 0
80                         && !scope.environment().options.reportUnusedDeclaredThrownExceptionWhenOverriding) {
81                     return;
82                 }
83                     
84                 // report errors for unreachable exception handlers
85                 for (int i = 0, count = handledExceptions.length; i < count; i++) {
86                         int index = indexes.get(handledExceptions[i]);
87                         int cacheIndex = index / BitCacheSize;
88                         int bitMask = 1 << (index % BitCacheSize);
89                         if ((isReached[cacheIndex] & bitMask) == 0) {
90                                 scope.problemReporter().unusedDeclaredThrownException(
91                                         handledExceptions[index],
92                                         method,
93                                         method.thrownExceptions[index]);
94                         }
95                 }
96         }
97         
98         public void complainIfUnusedExceptionHandlers(
99                 BlockScope scope,
100                 TryStatement tryStatement) {
101                 // report errors for unreachable exception handlers
102                 for (int i = 0, count = handledExceptions.length; i < count; i++) {
103                         int index = indexes.get(handledExceptions[i]);
104                         int cacheIndex = index / BitCacheSize;
105                         int bitMask = 1 << (index % BitCacheSize);
106                         if ((isReached[cacheIndex] & bitMask) == 0) {
107                                 scope.problemReporter().unreachableCatchBlock(
108                                         handledExceptions[index],
109                                         tryStatement.catchArguments[index].type);
110                         } else {
111                                 if ((isNeeded[cacheIndex] & bitMask) == 0) {
112                                         scope.problemReporter().hiddenCatchBlock(
113                                                 handledExceptions[index],
114                                                 tryStatement.catchArguments[index].type);
115                                 }
116                         }
117                 }
118         }
119
120         public String individualToString() {
121                 
122                 StringBuffer buffer = new StringBuffer("Exception flow context"); //$NON-NLS-1$
123                 int length = handledExceptions.length;
124                 for (int i = 0; i < length; i++) {
125                         int cacheIndex = i / BitCacheSize;
126                         int bitMask = 1 << (i % BitCacheSize);
127                         buffer.append('[').append(handledExceptions[i].readableName());
128                         if ((isReached[cacheIndex] & bitMask) != 0) {
129                                 if ((isNeeded[cacheIndex] & bitMask) == 0) {
130                                         buffer.append("-masked"); //$NON-NLS-1$
131                                 } else {
132                                         buffer.append("-reached"); //$NON-NLS-1$
133                                 }
134                         } else {
135                                 buffer.append("-not reached"); //$NON-NLS-1$
136                         }
137                         buffer.append('-').append(initsOnExceptions[i].toString()).append(']');
138                 }
139                 buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$
140                 return buffer.toString();
141         }
142
143         public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
144                 
145                 int index;
146                 if ((index = indexes.get(exceptionType)) < 0) {
147                         return FlowInfo.DEAD_END;
148                 }
149                 return initsOnExceptions[index];
150         }
151
152         public UnconditionalFlowInfo initsOnReturn(){
153                 return this.initsOnReturn;
154         }
155         
156         public void recordHandlingException(
157                 ReferenceBinding exceptionType,
158                 UnconditionalFlowInfo flowInfo,
159                 TypeBinding raisedException,
160                 ASTNode invocationSite,
161                 boolean wasAlreadyDefinitelyCaught) {
162                         
163                 int index = indexes.get(exceptionType);
164                 // if already flagged as being reached (unchecked exception handler)
165                 int cacheIndex = index / BitCacheSize;
166                 int bitMask = 1 << (index % BitCacheSize);
167                 if (!wasAlreadyDefinitelyCaught) {
168                         this.isNeeded[cacheIndex] |= bitMask;
169                 }
170                 this.isReached[cacheIndex] |= bitMask;
171                 
172                 initsOnExceptions[index] =
173                         initsOnExceptions[index] == FlowInfo.DEAD_END
174                                 ? flowInfo.copy().unconditionalInits()
175                                 : initsOnExceptions[index].mergedWith(flowInfo.copy().unconditionalInits());
176         }
177         
178         public void recordReturnFrom(FlowInfo flowInfo) {
179
180                 if (!flowInfo.isReachable()) return; 
181                 if (initsOnReturn == FlowInfo.DEAD_END) {
182                         initsOnReturn = flowInfo.copy().unconditionalInits();
183                 } else {
184                         initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits());
185                 }
186         }
187         
188         /*
189          * Compute a merged list of unhandled exception types (keeping only the most generic ones).
190          * This is necessary to add synthetic thrown exceptions for anonymous type constructors (JLS 8.6).
191          */
192         public void mergeUnhandledException(TypeBinding newException){
193                 
194                 if (this.extendedExceptions == null){
195                         this.extendedExceptions = new ArrayList(5);
196                         for (int i = 0; i < this.handledExceptions.length; i++){
197                                 this.extendedExceptions.add(this.handledExceptions[i]);
198                         }
199                 }
200                 
201                 boolean isRedundant = false;
202                 
203                 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){
204                         switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){
205                                 case MoreGeneric :
206                                         this.extendedExceptions.remove(i);
207                                         break;
208                                 case EqualOrMoreSpecific :
209                                         isRedundant = true;
210                                         break;
211                                 case NotRelated :
212                                         break;
213                         }
214                 }
215                 if (!isRedundant){
216                         this.extendedExceptions.add(newException);
217                 }
218         }
219 }