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
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.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;
24 * Reflects the context of code analysis, keeping track of enclosing
25 * try statements, exception handlers, etc...
27 public class ExceptionHandlingFlowContext extends FlowContext {
29 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.DeadEnd;
69 System.arraycopy(this.isReached, 0, this.isNeeded, 0, cacheSize);
70 this.initsOnReturn = FlowInfo.DeadEnd;
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 return buffer.toString();
120 public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
123 if ((index = indexes.get(exceptionType)) < 0) {
124 return FlowInfo.DeadEnd;
126 return initsOnExceptions[index];
129 public void recordHandlingException(
130 ReferenceBinding exceptionType,
131 UnconditionalFlowInfo flowInfo,
132 TypeBinding raisedException,
133 AstNode invocationSite,
134 boolean wasAlreadyDefinitelyCaught) {
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;
143 this.isReached[cacheIndex] |= bitMask;
144 initsOnExceptions[index] =
145 initsOnExceptions[index] == FlowInfo.DeadEnd
146 ? flowInfo.copy().unconditionalInits()
147 : initsOnExceptions[index].mergedWith(flowInfo);
150 public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
152 // record initializations which were performed at the return point
153 initsOnReturn = initsOnReturn.mergedWith(flowInfo);
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).
160 public void mergeUnhandledException(TypeBinding newException){
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]);
169 boolean isRedundant = false;
171 for(int i = this.extendedExceptions.size()-1; i >= 0; i--){
172 switch(Scope.compareTypes(newException, (TypeBinding)this.extendedExceptions.get(i))){
174 this.extendedExceptions.remove(i);
176 case EqualOrMoreSpecific :
184 this.extendedExceptions.add(newException);