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
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.codegen.ObjectCache;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
23 * Reflects the context of code analysis, keeping track of enclosing try
24 * statements, exception handlers, etc...
26 public class ExceptionHandlingFlowContext extends FlowContext {
28 public ReferenceBinding[] handledExceptions;
30 public final static int BitCacheSize = 32; // 32 bits per int
36 UnconditionalFlowInfo[] initsOnExceptions;
38 ObjectCache indexes = new ObjectCache();
40 boolean isMethodContext;
42 public UnconditionalFlowInfo initsOnReturn;
44 // for dealing with anonymous constructor thrown exceptions
45 public ArrayList extendedExceptions;
47 public ExceptionHandlingFlowContext(FlowContext parent,
48 ASTNode associatedNode, ReferenceBinding[] handledExceptions,
49 BlockScope scope, UnconditionalFlowInfo flowInfo) {
51 super(parent, associatedNode);
52 isMethodContext = scope == scope.methodScope();
53 this.handledExceptions = handledExceptions;
54 int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1;
55 this.isReached = new int[cacheSize]; // none is reached by default
56 this.isNeeded = new int[cacheSize]; // none is needed by default
57 this.initsOnExceptions = new UnconditionalFlowInfo[count];
58 for (int i = 0; i < count; i++) {
59 this.indexes.put(handledExceptions[i], i); // key type -> value
61 boolean isUnchecked = (scope
62 .compareUncheckedException(handledExceptions[i]) != NotRelated);
63 int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
65 isReached[cacheIndex] |= bitMask;
66 this.initsOnExceptions[i] = flowInfo.copy()
67 .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(
77 // ASTNode[] exceptionHandlers,
79 // TryStatement tryStatement) {
80 // // report errors for unreachable exception handlers
81 // for (int i = 0, count = handledExceptions.length; i < count; i++) {
82 // int index = indexes.get(handledExceptions[i]);
83 // int cacheIndex = index / BitCacheSize;
84 // int bitMask = 1 << (index % BitCacheSize);
85 // if ((isReached[cacheIndex] & bitMask) == 0) {
86 // scope.problemReporter().unreachableExceptionHandler(
87 // handledExceptions[index],
88 // exceptionHandlers[index]);
90 // if ((isNeeded[cacheIndex] & bitMask) == 0) {
91 // scope.problemReporter().maskedExceptionHandler(
92 // handledExceptions[index],
93 // exceptionHandlers[index]);
97 // // will optimized out unnecessary catch block during code gen
98 // tryStatement.preserveExceptionHandler = isNeeded;
101 public String individualToString() {
103 StringBuffer buffer = new StringBuffer("Exception flow context"); //$NON-NLS-1$
104 int length = handledExceptions.length;
105 for (int i = 0; i < length; i++) {
106 int cacheIndex = i / BitCacheSize;
107 int bitMask = 1 << (i % BitCacheSize);
108 buffer.append('[').append(handledExceptions[i].readableName());
109 if ((isReached[cacheIndex] & bitMask) != 0) {
110 if ((isNeeded[cacheIndex] & bitMask) == 0) {
111 buffer.append("-masked"); //$NON-NLS-1$
113 buffer.append("-reached"); //$NON-NLS-1$
116 buffer.append("-not reached"); //$NON-NLS-1$
118 buffer.append('-').append(initsOnExceptions[i].toString()).append(
122 .append("[initsOnReturn -").append(initsOnReturn.toString()).append(']'); //$NON-NLS-1$
123 return buffer.toString();
126 public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
129 if ((index = indexes.get(exceptionType)) < 0) {
130 return FlowInfo.DEAD_END;
132 return initsOnExceptions[index];
135 public UnconditionalFlowInfo initsOnReturn() {
136 return this.initsOnReturn;
139 public void recordHandlingException(ReferenceBinding exceptionType,
140 UnconditionalFlowInfo flowInfo, TypeBinding raisedException,
141 ASTNode invocationSite, boolean wasAlreadyDefinitelyCaught) {
143 int index = indexes.get(exceptionType);
144 // if already flagged as being reached (unchecked exception handler)
145 int cacheIndex = index / BitCacheSize;
146 int bitMask = 1 << (index % BitCacheSize);
147 if (!wasAlreadyDefinitelyCaught) {
148 this.isNeeded[cacheIndex] |= bitMask;
150 this.isReached[cacheIndex] |= bitMask;
152 initsOnExceptions[index] = initsOnExceptions[index] == FlowInfo.DEAD_END ? flowInfo
153 .copy().unconditionalInits()
154 : initsOnExceptions[index].mergedWith(flowInfo);
157 public void recordReturnFrom(FlowInfo flowInfo) {
159 if (!flowInfo.isReachable())
161 if (initsOnReturn == FlowInfo.DEAD_END) {
162 initsOnReturn = flowInfo.copy().unconditionalInits();
164 initsOnReturn = initsOnReturn.mergedWith(flowInfo
165 .unconditionalInits());
170 * Compute a merged list of unhandled exception types (keeping only the most
171 * generic ones). This is necessary to add synthetic thrown exceptions for
172 * anonymous type constructors (JLS 8.6).
174 public void mergeUnhandledException(TypeBinding newException) {
176 if (this.extendedExceptions == null) {
177 this.extendedExceptions = new ArrayList(5);
178 for (int i = 0; i < this.handledExceptions.length; i++) {
179 this.extendedExceptions.add(this.handledExceptions[i]);
183 boolean isRedundant = false;
185 for (int i = this.extendedExceptions.size() - 1; i >= 0; i--) {
186 switch (Scope.compareTypes(newException,
187 (TypeBinding) this.extendedExceptions.get(i))) {
189 this.extendedExceptions.remove(i);
191 case EqualOrMoreSpecific:
199 this.extendedExceptions.add(newException);