/*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v0.5
+ * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
package net.sourceforge.phpdt.internal.compiler.flow;
-import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
-import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
-import net.sourceforge.phpdt.internal.compiler.ast.Reference;
+import net.sourceforge.phpdt.core.compiler.CharOperation;
import net.sourceforge.phpdt.internal.compiler.codegen.Label;
import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
-import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
+import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
+import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
+import net.sourceforge.phpeclipse.internal.compiler.ast.Reference;
+import net.sourceforge.phpeclipse.internal.compiler.ast.TryStatement;
/**
* Reflects the context of code analysis, keeping track of enclosing
* try statements, exception handlers, etc...
*/
public class FlowContext implements TypeConstants {
- public AstNode associatedNode;
+
+ public ASTNode associatedNode;
public FlowContext parent;
- public final static FlowContext NotContinuableContext =
- new FlowContext(null, null);
+ public final static FlowContext NotContinuableContext = new FlowContext(null, null);
- public FlowContext(FlowContext parent, AstNode associatedNode) {
+ public FlowContext(FlowContext parent, ASTNode associatedNode) {
+
this.parent = parent;
this.associatedNode = associatedNode;
}
public Label breakLabel() {
+
return null;
}
public void checkExceptionHandlers(
TypeBinding[] raisedExceptions,
- AstNode location,
+ ASTNode location,
FlowInfo flowInfo,
BlockScope scope) {
0,
raisedCount);
FlowContext traversedContext = this;
+
while (traversedContext != null) {
- AstNode sub;
+ ASTNode sub;
if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) {
// traversing a non-returning subroutine means that all unhandled
// exceptions will actually never get sent...
return;
}
- // filter exceptions that are locally caught from the most enclosing
- // try statement to the outer ones.
+ // filter exceptions that are locally caught from the innermost enclosing
+ // try statement to the outermost ones.
if (traversedContext instanceof ExceptionHandlingFlowContext) {
ExceptionHandlingFlowContext exceptionContext =
(ExceptionHandlingFlowContext) traversedContext;
for (int i = 0; i < raisedCount; i++) {
TypeBinding raisedException;
if ((raisedException = raisedExceptions[i]) != null) {
- if (scope
- .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException())
- || scope.areTypesCompatible(raisedException, scope.getJavaLangError())) {
+ if (raisedException.isCompatibleWith(scope.getJavaLangRuntimeException())
+ || raisedException.isCompatibleWith(scope.getJavaLangError())) {
remainingCount--;
raisedExceptions[i] = null;
}
}
if (remainingCount == 0)
return;
+
+ traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
+ if (traversedContext.associatedNode instanceof TryStatement){
+ flowInfo = flowInfo.copy().addInitializationsFrom(((TryStatement) traversedContext.associatedNode).subRoutineInits);
+ }
traversedContext = traversedContext.parent;
}
// if reaches this point, then there are some remaining unhandled exception types.
- for (int i = 0; i < raisedCount; i++) {
+ nextReport: for (int i = 0; i < raisedCount; i++) {
TypeBinding exception;
if ((exception = raisedExceptions[i]) != null) {
+ // only one complaint if same exception declared to be thrown more than once
+ for (int j = 0; j < i; j++) {
+ if (raisedExceptions[j] == exception) continue nextReport; // already reported
+ }
scope.problemReporter().unhandledException(exception, location);
}
}
public void checkExceptionHandlers(
TypeBinding raisedException,
- AstNode location,
+ ASTNode location,
FlowInfo flowInfo,
BlockScope scope) {
// until the point where it is safely handled (Smarter - see comment at the end)
FlowContext traversedContext = this;
while (traversedContext != null) {
- AstNode sub;
+ ASTNode sub;
if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) {
// traversing a non-returning subroutine means that all unhandled
// exceptions will actually never get sent...
return;
}
- // filter exceptions that are locally caught from the most enclosing
- // try statement to the outer ones.
+
+ // filter exceptions that are locally caught from the innermost enclosing
+ // try statement to the outermost ones.
if (traversedContext instanceof ExceptionHandlingFlowContext) {
ExceptionHandlingFlowContext exceptionContext =
(ExceptionHandlingFlowContext) traversedContext;
}
// method treatment for unchecked exceptions
if (exceptionContext.isMethodContext) {
- if (scope
- .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException())
- || scope.areTypesCompatible(raisedException, scope.getJavaLangError()))
+ if (raisedException.isCompatibleWith(scope.getJavaLangRuntimeException())
+ || raisedException.isCompatibleWith(scope.getJavaLangError()))
return;
// anonymous constructors are allowed to throw any exceptions (their thrown exceptions
break; // not handled anywhere, thus jump to error handling
}
}
+
+ traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
+ if (traversedContext.associatedNode instanceof TryStatement){
+ flowInfo = flowInfo.copy().addInitializationsFrom(((TryStatement) traversedContext.associatedNode).subRoutineInits);
+ }
traversedContext = traversedContext.parent;
}
// if reaches this point, then there are some remaining unhandled exception types.
}
public Label continueLabel() {
+
return null;
}
* lookup through break labels
*/
public FlowContext getTargetContextForBreakLabel(char[] labelName) {
+
FlowContext current = this, lastNonReturningSubRoutine = null;
while (current != null) {
if (current.isNonReturningContext()) {
* lookup through continue labels
*/
public FlowContext getTargetContextForContinueLabel(char[] labelName) {
- FlowContext current = this,
- lastContinuable = null,
- lastNonReturningSubRoutine = null;
+
+ FlowContext current = this;
+ FlowContext lastContinuable = null;
+ FlowContext lastNonReturningSubRoutine = null;
+
while (current != null) {
if (current.isNonReturningContext()) {
lastNonReturningSubRoutine = current;
lastContinuable = current;
}
}
+
char[] currentLabelName;
- if (((currentLabelName = current.labelName()) != null)
- && CharOperation.equals(currentLabelName, labelName)) {
+ if ((currentLabelName = current.labelName()) != null && CharOperation.equals(currentLabelName, labelName)) {
+
+ // matching label found
if ((lastContinuable != null)
- && (current.associatedNode.concreteStatement()
- == lastContinuable.associatedNode)) {
+ && (current.associatedNode.concreteStatement() == lastContinuable.associatedNode)) {
+
if (lastNonReturningSubRoutine == null) {
return lastContinuable;
} else {
* lookup a default break through breakable locations
*/
public FlowContext getTargetContextForDefaultBreak() {
+
FlowContext current = this, lastNonReturningSubRoutine = null;
while (current != null) {
if (current.isNonReturningContext()) {
lastNonReturningSubRoutine = current;
}
- if (current.isBreakable()) {
+ if (current.isBreakable() && current.labelName() == null) {
if (lastNonReturningSubRoutine == null) {
return current;
} else {
* lookup a default continue amongst continuable locations
*/
public FlowContext getTargetContextForDefaultContinue() {
+
FlowContext current = this, lastNonReturningSubRoutine = null;
while (current != null) {
if (current.isNonReturningContext()) {
}
public String individualToString() {
+
return "Flow context"; //$NON-NLS-1$
}
public FlowInfo initsOnBreak() {
- return FlowInfo.DeadEnd;
+
+ return FlowInfo.DEAD_END;
+ }
+
+ public UnconditionalFlowInfo initsOnReturn() {
+
+ return FlowInfo.DEAD_END;
}
public boolean isBreakable() {
+
return false;
}
public boolean isContinuable() {
+
return false;
}
public boolean isNonReturningContext() {
+
return false;
}
public boolean isSubRoutine() {
+
return false;
}
public char[] labelName() {
+
return null;
}
boolean recordFinalAssignment(
VariableBinding variable,
Reference finalReference) {
+
return true; // keep going
}
- public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
+ public void recordReturnFrom(FlowInfo flowInfo) {
}
public void recordSettingFinal(
VariableBinding variable,
Reference finalReference) {
+
// for initialization inside looping statement that effectively loops
FlowContext context = this;
while (context != null) {
void removeFinalAssignmentIfAny(Reference reference) {
}
- public AstNode subRoutine() {
+ public ASTNode subRoutine() {
+
return null;
}
public String toString() {
+
StringBuffer buffer = new StringBuffer();
FlowContext current = this;
int parentsCount = 0;
buffer.append(individualToString()).append('\n');
return buffer.toString();
}
-}
\ No newline at end of file
+}