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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.flow;
13 import java.util.ArrayList;
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;
27 * Reflects the context of code analysis, keeping track of enclosing
28 * try statements, exception handlers, etc...
30 public class ExceptionHandlingFlowContext extends FlowContext {
32 public ReferenceBinding[] handledExceptions;
34 public final static int BitCacheSize = 32; // 32 bits per int
37 UnconditionalFlowInfo[] initsOnExceptions;
38 ObjectCache indexes = new ObjectCache();
39 boolean isMethodContext;
41 public UnconditionalFlowInfo initsOnReturn;
43 // for dealing with anonymous constructor thrown exceptions
44 public ArrayList extendedExceptions;
46 public ExceptionHandlingFlowContext(
48 ASTNode associatedNode,
49 ReferenceBinding[] handledExceptions,
51 UnconditionalFlowInfo flowInfo) {
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
63 (scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
64 int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
66 isReached[cacheIndex] |= bitMask;
67 this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
69 this.initsOnExceptions[i] = FlowInfo.DEAD_END;
72 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize);
73 this.initsOnReturn = FlowInfo.DEAD_END;
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) {
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],
93 method.thrownExceptions[index]);
98 public void complainIfUnusedExceptionHandlers(
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);
111 if ((isNeeded[cacheIndex] & bitMask) == 0) {
112 scope.problemReporter().hiddenCatchBlock(
113 handledExceptions[index],
114 tryStatement.catchArguments[index].type);
120 public String individualToString() {
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$
132 buffer.append("-reached"); //$NON-NLS-1$
135 buffer.append("-not reached"); //$NON-NLS-1$
137 buffer.append('-').append(initsOnExceptions[i].toString()).append(']');
139 buffer.append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$
140 return buffer.toString();
143 public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
146 if ((index = indexes.get(exceptionType)) < 0) {
147 return FlowInfo.DEAD_END;
149 return initsOnExceptions[index];
152 public UnconditionalFlowInfo initsOnReturn(){
153 return this.initsOnReturn;
156 public void recordHandlingException(
157 ReferenceBinding exceptionType,
158 UnconditionalFlowInfo flowInfo,
159 TypeBinding raisedException,
160 ASTNode invocationSite,
161 boolean wasAlreadyDefinitelyCaught) {
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;
170 this.isReached[cacheIndex] |= bitMask;
172 initsOnExceptions[index] =
173 initsOnExceptions[index] == FlowInfo.DEAD_END
174 ? flowInfo.copy().unconditionalInits()
175 : initsOnExceptions[index].mergedWith(flowInfo.copy().unconditionalInits());
178 public void recordReturnFrom(FlowInfo flowInfo) {
180 if (!flowInfo.isReachable()) return;
181 if (initsOnReturn == FlowInfo.DEAD_END) {
182 initsOnReturn = flowInfo.copy().unconditionalInits();
184 initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits());
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).
192 public void mergeUnhandledException(TypeBinding newException){
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]);
201 boolean isRedundant = false;
203 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){
204 switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){
206 this.extendedExceptions.remove(i);
208 case EqualOrMoreSpecific :
216 this.extendedExceptions.add(newException);