Refactory: smarty.ui plugin.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / flow / FlowContext.java
index 60196d0..8daeeba 100644 (file)
@@ -1,18 +1,20 @@
 /*******************************************************************************
- * 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.core.compiler.CharOperation;
+import net.sourceforge.phpdt.internal.compiler.ast.ASTNode;
 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.internal.compiler.ast.TryStatement;
 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,99 +22,102 @@ 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;
 
 /**
- * Reflects the context of code analysis, keeping track of enclosing
- *     try statements, exception handlers, etc...
+ * 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 FlowContext(FlowContext parent, AstNode associatedNode) {
+       public final static FlowContext NotContinuableContext = new FlowContext(
+                       null, null);
+
+       public FlowContext(FlowContext parent, ASTNode associatedNode) {
+
                this.parent = parent;
                this.associatedNode = associatedNode;
        }
-       
+
        public Label breakLabel() {
+
                return null;
        }
-       
-       public void checkExceptionHandlers(
-               TypeBinding[] raisedExceptions,
-               AstNode location,
-               FlowInfo flowInfo,
-               BlockScope scope) {
+
+       public void checkExceptionHandlers(TypeBinding[] raisedExceptions,
+                       ASTNode location, FlowInfo flowInfo, BlockScope scope) {
 
                // check that all the argument exception types are handled
-               // JDK Compatible implementation - when an exception type is thrown, 
-               // all related catch blocks are marked as reachable... instead of those only
-               // until the point where it is safely handled (Smarter - see comment at the end)
-               int remainingCount; // counting the number of remaining unhandled exceptions
+               // JDK Compatible implementation - when an exception type is thrown,
+               // all related catch blocks are marked as reachable... instead of those
+               // only
+               // until the point where it is safely handled (Smarter - see comment at
+               // the end)
+               int remainingCount; // counting the number of remaining unhandled
+                                                       // exceptions
                int raisedCount; // total number of exceptions raised
                if ((raisedExceptions == null)
-                       || ((raisedCount = raisedExceptions.length) == 0))
+                               || ((raisedCount = raisedExceptions.length) == 0))
                        return;
                remainingCount = raisedCount;
 
                // duplicate the array of raised exceptions since it will be updated
                // (null replaces any handled exception)
-               System.arraycopy(
-                       raisedExceptions,
-                       0,
-                       (raisedExceptions = new TypeBinding[raisedCount]),
-                       0,
-                       raisedCount);
+               System.arraycopy(raisedExceptions, 0,
+                               (raisedExceptions = new TypeBinding[raisedCount]), 0,
+                               raisedCount);
                FlowContext traversedContext = this;
+
                while (traversedContext != null) {
-                       AstNode sub;
-                       if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) {
-                               // traversing a non-returning subroutine means that all unhandled 
+                       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;
+                               ExceptionHandlingFlowContext exceptionContext = (ExceptionHandlingFlowContext) traversedContext;
                                ReferenceBinding[] caughtExceptions;
                                if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) {
                                        int caughtCount = caughtExceptions.length;
-                                       boolean[] locallyCaught = new boolean[raisedCount]; // at most
+                                       boolean[] locallyCaught = new boolean[raisedCount]; // at
+                                                                                                                                               // most
 
                                        for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) {
                                                ReferenceBinding caughtException = caughtExceptions[caughtIndex];
                                                for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) {
                                                        TypeBinding raisedException;
                                                        if ((raisedException = raisedExceptions[raisedIndex]) != null) {
-                                                               switch (Scope.compareTypes(raisedException, caughtException)) {
-                                                                       case EqualOrMoreSpecific :
-                                                                               exceptionContext.recordHandlingException(
-                                                                                       caughtException,
-                                                                                       flowInfo.unconditionalInits(),
-                                                                                       raisedException,
-                                                                                       location,
+                                                               switch (Scope.compareTypes(raisedException,
+                                                                               caughtException)) {
+                                                               case EqualOrMoreSpecific:
+                                                                       exceptionContext.recordHandlingException(
+                                                                                       caughtException, flowInfo
+                                                                                                       .unconditionalInits(),
+                                                                                       raisedException, location,
                                                                                        locallyCaught[raisedIndex]);
-                                                                               // was already definitely caught ?
-                                                                               if (!locallyCaught[raisedIndex]) {
-                                                                                       locallyCaught[raisedIndex] = true;
-                                                                                       // remember that this exception has been definitely caught
-                                                                                       remainingCount--;
-                                                                               }
-                                                                               break;
-                                                                       case MoreGeneric :
-                                                                               exceptionContext.recordHandlingException(
-                                                                                       caughtException,
-                                                                                       flowInfo.unconditionalInits(),
-                                                                                       raisedException,
-                                                                                       location,
-                                                                                       false);
-                                                                               // was not caught already per construction
+                                                                       // was already definitely caught ?
+                                                                       if (!locallyCaught[raisedIndex]) {
+                                                                               locallyCaught[raisedIndex] = true;
+                                                                               // remember that this exception has been
+                                                                               // definitely caught
+                                                                               remainingCount--;
+                                                                       }
+                                                                       break;
+                                                               case MoreGeneric:
+                                                                       exceptionContext.recordHandlingException(
+                                                                                       caughtException, flowInfo
+                                                                                                       .unconditionalInits(),
+                                                                                       raisedException, location, false);
+                                                                       // was not caught already per construction
                                                                }
                                                        }
                                                }
@@ -120,7 +125,8 @@ public class FlowContext implements TypeConstants {
                                        // remove locally caught exceptions from the remaining ones
                                        for (int i = 0; i < raisedCount; i++) {
                                                if (locallyCaught[i]) {
-                                                       raisedExceptions[i] = null; // removed from the remaining ones.
+                                                       raisedExceptions[i] = null; // removed from the
+                                                                                                               // remaining ones.
                                                }
                                        }
                                }
@@ -129,27 +135,33 @@ public class FlowContext implements TypeConstants {
                                        for (int i = 0; i < raisedCount; i++) {
                                                TypeBinding raisedException;
                                                if ((raisedException = raisedExceptions[i]) != null) {
-                                                       if (BlockScope
-                                                               .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException())
-                                                               || BlockScope.areTypesCompatible(raisedException, scope.getJavaLangError())) {
+                                                       if (raisedException.isCompatibleWith(scope
+                                                                       .getJavaLangRuntimeException())
+                                                                       || raisedException.isCompatibleWith(scope
+                                                                                       .getJavaLangError())) {
                                                                remainingCount--;
                                                                raisedExceptions[i] = null;
                                                        }
                                                }
                                        }
-                                       // anonymous constructors are allowed to throw any exceptions (their thrown exceptions
+                                       // anonymous constructors are allowed to throw any
+                                       // exceptions (their thrown exceptions
                                        // clause will be fixed up later as per JLS 8.6).
-                                       if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){
-                                               AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode;
-                                               if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){
-                                                               
+                                       if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration) {
+                                               AbstractMethodDeclaration method = (AbstractMethodDeclaration) exceptionContext.associatedNode;
+                                               if (method.isConstructor()
+                                                               && method.binding.declaringClass
+                                                                               .isAnonymousType()) {
+
                                                        for (int i = 0; i < raisedCount; i++) {
                                                                TypeBinding raisedException;
                                                                if ((raisedException = raisedExceptions[i]) != null) {
-                                                                       exceptionContext.mergeUnhandledException(raisedException);
+                                                                       exceptionContext
+                                                                                       .mergeUnhandledException(raisedException);
                                                                }
                                                        }
-                                                       return; // no need to complain, will fix up constructor exceptions                                              
+                                                       return; // no need to complain, will fix up
+                                                                       // constructor exceptions
                                                }
                                        }
                                        break; // not handled anywhere, thus jump to error handling
@@ -157,67 +169,80 @@ 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++) {
+               // if reaches this point, then there are some remaining unhandled
+               // exception types.
+               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,
-               FlowInfo flowInfo,
-               BlockScope scope) {
+       public void checkExceptionHandlers(TypeBinding raisedException,
+                       ASTNode location, FlowInfo flowInfo, BlockScope scope) {
 
                // LIGHT-VERSION OF THE EQUIVALENT WITH AN ARRAY OF EXCEPTIONS
                // check that all the argument exception types are handled
-               // JDK Compatible implementation - when an exception type is thrown, 
-               // all related catch blocks are marked as reachable... instead of those only
-               // until the point where it is safely handled (Smarter - see comment at the end)
+               // JDK Compatible implementation - when an exception type is thrown,
+               // all related catch blocks are marked as reachable... instead of those
+               // only
+               // until the point where it is safely handled (Smarter - see comment at
+               // the end)
                FlowContext traversedContext = this;
                while (traversedContext != null) {
-                       AstNode sub;
-                       if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) {
-                               // traversing a non-returning subroutine means that all unhandled 
+                       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;
+                               ExceptionHandlingFlowContext exceptionContext = (ExceptionHandlingFlowContext) traversedContext;
                                ReferenceBinding[] caughtExceptions;
                                if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) {
                                        boolean definitelyCaught = false;
-                                       for (int caughtIndex = 0, caughtCount = caughtExceptions.length;
-                                               caughtIndex < caughtCount;
-                                               caughtIndex++) {
+                                       for (int caughtIndex = 0, caughtCount = caughtExceptions.length; caughtIndex < caughtCount; caughtIndex++) {
                                                ReferenceBinding caughtException = caughtExceptions[caughtIndex];
-                                               switch (Scope.compareTypes(raisedException, caughtException)) {
-                                                       case EqualOrMoreSpecific :
-                                                               exceptionContext.recordHandlingException(
-                                                                       caughtException,
-                                                                       flowInfo.unconditionalInits(),
-                                                                       raisedException,
-                                                                       location,
-                                                                       definitelyCaught);
-                                                               // was it already definitely caught ?
-                                                               definitelyCaught = true;
-                                                               break;
-                                                       case MoreGeneric :
-                                                               exceptionContext.recordHandlingException(
-                                                                       caughtException,
-                                                                       flowInfo.unconditionalInits(),
-                                                                       raisedException,
-                                                                       location,
-                                                                       false);
-                                                               // was not caught already per construction
+                                               switch (Scope.compareTypes(raisedException,
+                                                               caughtException)) {
+                                               case EqualOrMoreSpecific:
+                                                       exceptionContext
+                                                                       .recordHandlingException(caughtException,
+                                                                                       flowInfo.unconditionalInits(),
+                                                                                       raisedException, location,
+                                                                                       definitelyCaught);
+                                                       // was it already definitely caught ?
+                                                       definitelyCaught = true;
+                                                       break;
+                                               case MoreGeneric:
+                                                       exceptionContext.recordHandlingException(
+                                                                       caughtException, flowInfo
+                                                                                       .unconditionalInits(),
+                                                                       raisedException, location, false);
+                                                       // was not caught already per construction
                                                }
                                        }
                                        if (definitelyCaught)
@@ -225,31 +250,47 @@ public class FlowContext implements TypeConstants {
                                }
                                // method treatment for unchecked exceptions
                                if (exceptionContext.isMethodContext) {
-                                       if (BlockScope
-                                               .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException())
-                                               || BlockScope.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
+
+                                       // anonymous constructors are allowed to throw any
+                                       // exceptions (their thrown exceptions
                                        // clause will be fixed up later as per JLS 8.6).
-                                       if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){
-                                               AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode;
-                                               if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){
-                                                                       
-                                                       exceptionContext.mergeUnhandledException(raisedException);
-                                                       return; // no need to complain, will fix up constructor exceptions                                              
+                                       if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration) {
+                                               AbstractMethodDeclaration method = (AbstractMethodDeclaration) exceptionContext.associatedNode;
+                                               if (method.isConstructor()
+                                                               && method.binding.declaringClass
+                                                                               .isAnonymousType()) {
+
+                                                       exceptionContext
+                                                                       .mergeUnhandledException(raisedException);
+                                                       return; // no need to complain, will fix up
+                                                                       // constructor 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.
+               // if reaches this point, then there are some remaining unhandled
+               // exception types.
                scope.problemReporter().unhandledException(raisedException, location);
        }
 
        public Label continueLabel() {
+
                return null;
        }
 
@@ -257,6 +298,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()) {
@@ -264,7 +306,7 @@ public class FlowContext implements TypeConstants {
                        }
                        char[] currentLabelName;
                        if (((currentLabelName = current.labelName()) != null)
-                               && CharOperation.equals(currentLabelName, labelName)) {
+                                       && CharOperation.equals(currentLabelName, labelName)) {
                                if (lastNonReturningSubRoutine == null) {
                                        return current;
                                } else {
@@ -281,9 +323,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 +336,15 @@ 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 +365,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 +388,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 +408,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;
        }
 
@@ -392,18 +453,18 @@ public class FlowContext implements TypeConstants {
        public void recordContinueFrom(FlowInfo flowInfo) {
        }
 
-       boolean recordFinalAssignment(
-               VariableBinding variable,
-               Reference finalReference) {
+       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) {
+       public void recordSettingFinal(VariableBinding variable,
+                       Reference finalReference) {
+
                // for initialization inside looping statement that effectively loops
                FlowContext context = this;
                while (context != null) {
@@ -417,11 +478,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 +509,4 @@ public class FlowContext implements TypeConstants {
                buffer.append(individualToString()).append('\n');
                return buffer.toString();
        }
-}
\ No newline at end of file
+}