Syntax highlighting is changeable.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / flow / FlowContext.java
index e92b862..11624b5 100644 (file)
@@ -1,18 +1,16 @@
 /*******************************************************************************
- * 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;
@@ -20,31 +18,36 @@ import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
 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) {
 
@@ -68,15 +71,16 @@ public class FlowContext implements TypeConstants {
                        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;
@@ -129,9 +133,8 @@ public class FlowContext implements TypeConstants {
                                        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;
                                                        }
@@ -157,12 +160,21 @@ public class FlowContext implements TypeConstants {
                        }
                        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);
                        }
                }
@@ -170,7 +182,7 @@ public class FlowContext implements TypeConstants {
 
        public void checkExceptionHandlers(
                TypeBinding raisedException,
-               AstNode location,
+               ASTNode location,
                FlowInfo flowInfo,
                BlockScope scope) {
 
@@ -181,14 +193,15 @@ public class FlowContext implements TypeConstants {
                // 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;
@@ -225,9 +238,8 @@ public class FlowContext implements TypeConstants {
                                }
                                // 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
@@ -243,6 +255,11 @@ public class FlowContext implements TypeConstants {
                                        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.
@@ -250,6 +267,7 @@ public class FlowContext implements TypeConstants {
        }
 
        public Label continueLabel() {
+
                return null;
        }
 
@@ -257,6 +275,7 @@ public class FlowContext implements TypeConstants {
         * lookup through break labels
         */
        public FlowContext getTargetContextForBreakLabel(char[] labelName) {
+
                FlowContext current = this, lastNonReturningSubRoutine = null;
                while (current != null) {
                        if (current.isNonReturningContext()) {
@@ -281,9 +300,11 @@ public class FlowContext implements TypeConstants {
         * 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;
@@ -292,12 +313,14 @@ public class FlowContext implements TypeConstants {
                                        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 {
@@ -318,12 +341,13 @@ public class FlowContext implements TypeConstants {
         * 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 {
@@ -340,6 +364,7 @@ public class FlowContext implements TypeConstants {
         * lookup a default continue amongst continuable locations
         */
        public FlowContext getTargetContextForDefaultContinue() {
+
                FlowContext current = this, lastNonReturningSubRoutine = null;
                while (current != null) {
                        if (current.isNonReturningContext()) {
@@ -359,30 +384,42 @@ public class FlowContext implements TypeConstants {
        }
 
        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;
        }
 
@@ -395,15 +432,17 @@ public class FlowContext implements TypeConstants {
        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) {
@@ -417,11 +456,13 @@ public class FlowContext implements TypeConstants {
        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;
@@ -446,4 +487,4 @@ public class FlowContext implements TypeConstants {
                buffer.append(individualToString()).append('\n');
                return buffer.toString();
        }
-}
\ No newline at end of file
+}