New Warning: "Uninitialized local variable"
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
index 908fbf8..d3e2a3c 100644 (file)
@@ -9,6 +9,8 @@ package net.sourceforge.phpdt.internal.compiler.parser;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Stack;
 
 import net.sourceforge.phpdt.core.compiler.CharOperation;
 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
@@ -308,6 +310,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
    */
   public void parse(String s, HashMap variables) {
     fMethodVariables = variables;
+    fStackUnassigned = new Stack();
     init(s);
     parse();
   }
@@ -470,8 +473,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       try {
         statement = statement();
         blockStatements.add(statement);
-        if (branchStatement && statement!=null) {
-          reportSyntaxError("Unreachable code", statement.sourceStart, statement.sourceEnd);
+        if (branchStatement && statement != null) {
+//          reportSyntaxError("Unreachable code", statement.sourceStart, statement.sourceEnd);
+          problemReporter.unreachableCode(new String(scanner.getCurrentIdentifierSource()),statement.sourceStart, statement.sourceEnd,
+              referenceContext, compilationUnit.compilationResult);
         }
         if ((token == TokenNameRBRACE) || (token == TokenNamecase) || (token == TokenNamedefault) || (token == TokenNameelse)
             || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor)
@@ -525,7 +530,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
   private boolean checkUnreachableStatements(Statement statement) {
     if (statement instanceof ReturnStatement || statement instanceof ContinueStatement || statement instanceof BreakStatement) {
       return true;
-    } else if (statement instanceof IfStatement && ((IfStatement)statement).checkUnreachable) {
+    } else if (statement instanceof IfStatement && ((IfStatement) statement).checkUnreachable) {
       return true;
     }
     return false;
@@ -718,7 +723,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       foreach_optional_arg();
       if (token == TokenNameEQUAL_GREATER) {
         getNextToken();
-        variable();
+        variable(false);
       }
       if (token == TokenNameRPAREN) {
         getNextToken();
@@ -1059,7 +1064,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     if (token == TokenNameAND) {
       getNextToken();
     }
-    w_variable();
+    w_variable(true);
   }
 
   private void foreach_optional_arg() {
@@ -1075,8 +1080,9 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     //  global_var_list:
     // global_var_list ',' global_var
     //| global_var
+    HashSet set = peekVariableSet();
     while (true) {
-      global_var();
+      global_var(set);
       if (token != TokenNameCOMMA) {
         break;
       }
@@ -1084,16 +1090,17 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     }
   }
 
-  private void global_var() {
+  private void global_var(HashSet set) {
     //global_var:
     // T_VARIABLE
     //| '$' r_variable
     //| '$' '{' expr '}'
     if (token == TokenNameVariable) {
-      VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_GLOBAL_VAR);
       if (fMethodVariables != null) {
+        VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_GLOBAL_VAR);
         fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
       }
+      addVariableSet(set);
       getNextToken();
     } else if (token == TokenNameDOLLAR) {
       getNextToken();
@@ -1115,13 +1122,15 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     // static_var_list ',' T_VARIABLE
     //| static_var_list ',' T_VARIABLE '=' static_scalar
     //| T_VARIABLE
-    //| T_VARIABLE '=' static_scalar
+    //| T_VARIABLE '=' static_scalar,
+    HashSet set = peekVariableSet();
     while (true) {
       if (token == TokenNameVariable) {
-        VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_STATIC_VAR);
         if (fMethodVariables != null) {
+          VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_STATIC_VAR);
           fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
-        }
+        } 
+        addVariableSet(set);
         getNextToken();
         if (token == TokenNameEQUAL) {
           getNextToken();
@@ -1144,7 +1153,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     //    unset_variable:
     //                 variable
     while (true) {
-      variable();
+      variable(false);
       if (token != TokenNameCOMMA) {
         break;
       }
@@ -1607,15 +1616,20 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
         }
       }
     }
-    functionDeclarator(methodDecl);
-    if (token == TokenNameSEMICOLON) {
-      if (!isAbstract) {
-        throwSyntaxError("Body declaration expected for method: " + new String(methodDecl.selector));
+    try {
+      pushVariableSet();
+      functionDeclarator(methodDecl);
+      if (token == TokenNameSEMICOLON) {
+        if (!isAbstract) {
+          throwSyntaxError("Body declaration expected for method: " + new String(methodDecl.selector));
+        }
+        getNextToken();
+        return;
       }
-      getNextToken();
-      return;
+      functionBody(methodDecl);
+    } finally {
+      fStackUnassigned.pop();
     }
-    functionBody(methodDecl);
   }
 
   private void functionDeclarator(MethodDeclaration methodDecl) {
@@ -1672,6 +1686,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     // static_scalar
     char[] typeIdentifier = null;
     if (token == TokenNameIdentifier || token == TokenNameVariable || token == TokenNameAND) {
+      HashSet set = peekVariableSet();
       while (true) {
         if (token == TokenNameIdentifier) {
           typeIdentifier = scanner.getCurrentIdentifierSource();
@@ -1691,6 +1706,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
             info.typeIdentifier = typeIdentifier;
             fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
           }
+          addVariableSet(set);
           getNextToken();
           if (token == TokenNameEQUAL) {
             getNextToken();
@@ -1799,7 +1815,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     checkUnreachable(iState, b);
     if (token == TokenNameelseif) {
       new_elseif_list(iState);
-    } 
+    }
     new_else_single(iState);
     if (token != TokenNameendif) {
       throwSyntaxError("'endif' expected.");
@@ -1943,14 +1959,14 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
         int off = b.statements.length - 1;
         if (!(b.statements[off] instanceof ReturnStatement) && !(b.statements[off] instanceof ContinueStatement)
             && !(b.statements[off] instanceof BreakStatement)) {
-          if (!(b.statements[off] instanceof IfStatement) || !((IfStatement)b.statements[off]).checkUnreachable) {
+          if (!(b.statements[off] instanceof IfStatement) || !((IfStatement) b.statements[off]).checkUnreachable) {
             iState.checkUnreachable = false;
           }
-        } 
+        }
       }
     } else {
       if (!(s instanceof ReturnStatement) && !(s instanceof ContinueStatement) && !(s instanceof BreakStatement)) {
-        if (!(s instanceof IfStatement) || !((IfStatement)s).checkUnreachable) {
+        if (!(s instanceof IfStatement) || !((IfStatement) s).checkUnreachable) {
           iState.checkUnreachable = false;
         }
       }
@@ -2420,9 +2436,17 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       case TokenNameVariable:
       case TokenNameDOLLAR:
         boolean rememberedVar = false;
-        Expression lhs = variable();
+//        char[] lhsVar = null;
+//        if (token==TokenNameVariable) {
+//          lhsVar = scanner.getCurrentTokenSource();
+//        }
+        Expression lhs = variable(true);
+
         switch (token) {
         case TokenNameEQUAL:
+//          if (lhsVar != null) {
+//            addVariableSet(lhsVar);
+//          }
           getNextToken();
           if (token == TokenNameAND) {
             getNextToken();
@@ -2446,7 +2470,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                 }
               }
             } else {
-              Expression rhs = variable();
+              Expression rhs = variable(false);
               if (rhs != null && rhs instanceof FieldReference && lhs != null && lhs instanceof FieldReference) {
                 // example:
                 // $var = &$ref;
@@ -2734,8 +2758,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     // variable
     //| T_LIST '(' assignment_list ')'
     //| /* empty */
-    if (token == TokenNameVariable || token == TokenNameDOLLAR) {
-      variable();
+    if (token == TokenNameVariable) {
+      variable(true);
+    } else if (token == TokenNameDOLLAR) {
+      variable(false);
     } else {
       if (token == TokenNamelist) {
         getNextToken();
@@ -2776,17 +2802,17 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     while (true) {
       if (token == TokenNameAND) {
         getNextToken();
-        variable();
+        variable(false);
       } else {
         expr();
         if (token == TokenNameAND) {
           getNextToken();
-          variable();
+          variable(false);
         } else if (token == TokenNameEQUAL_GREATER) {
           getNextToken();
           if (token == TokenNameAND) {
             getNextToken();
-            variable();
+            variable(false);
           } else {
             expr();
           }
@@ -2812,7 +2838,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
   //      }
   //    } while (true);
   //  }
-  private Expression variable_without_objects() {
+  private Expression variable_without_objects(boolean lefthandside) {
     //  variable_without_objects:
     //                 reference_variable
     //         | simple_indirect_reference reference_variable
@@ -2822,10 +2848,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     while (token == TokenNameDOLLAR) {
       getNextToken();
     }
-    return reference_variable();
+    return reference_variable(lefthandside);
   }
 
-  private Expression function_call() {
+  private Expression function_call(boolean lefthandside) {
     //  function_call:
     // T_STRING '(' function_call_parameter_list ')'
     //| class_constant '(' function_call_parameter_list ')'
@@ -2855,12 +2881,12 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
           getNextToken();
         } else {
           //        static member:
-          variable_without_objects();
+          variable_without_objects(false);
         }
         break;
       }
     } else {
-      ref = variable_without_objects();
+      ref = variable_without_objects(lefthandside);
     }
     if (token != TokenNameLPAREN) {
       if (defineName != null) {
@@ -2931,7 +2957,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     while (true) {
       if (token == TokenNameAND) {
         getNextToken();
-        w_variable();
+        w_variable(false);
       } else {
         //        if (token == TokenNameIdentifier || token ==
         // TokenNameVariable
@@ -2968,10 +2994,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       throwSyntaxError("'::' expected after class name (static_member).");
     }
     getNextToken();
-    variable_without_objects();
+    variable_without_objects(false);
   }
 
-  private Expression base_variable_with_function_calls() {
+  private Expression base_variable_with_function_calls(boolean lefthandside) {
     //  base_variable_with_function_calls:
     // base_variable
     //| function_call
@@ -2993,7 +3019,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     //      scanner.phpMode = true;
     //    }
     //    if (functionCall) {
-    return function_call();
+    return function_call(lefthandside);
     //    } else {
     //      base_variable();
     //    }
@@ -3014,7 +3040,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       while (token == TokenNameDOLLAR) {
         getNextToken();
       }
-      reference_variable();
+      reference_variable(false);
     }
     return ref;
   }
@@ -3024,7 +3050,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
   //    // '$'
   //    //| simple_indirect_reference '$'
   //  }
-  private Expression reference_variable() {
+  private Expression reference_variable(boolean lefthandside) {
     //  reference_variable:
     //                 reference_variable '[' dim_offset ']'
     //         | reference_variable '{' expr '}'
@@ -3033,7 +3059,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     if (Scanner.TRACE) {
       System.out.println("TRACE: reference_variable()");
     }
-    ref = compound_variable();
+    ref = compound_variable(lefthandside);
     while (true) {
       if (token == TokenNameLBRACE) {
         ref = null;
@@ -3061,7 +3087,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     return ref;
   }
 
-  private Expression compound_variable() {
+  private Expression compound_variable(boolean lefthandside) {
     //  compound_variable:
     //                 T_VARIABLE
     //         | '$' '{' expr '}'
@@ -3069,6 +3095,16 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       System.out.println("TRACE: compound_variable()");
     }
     if (token == TokenNameVariable) {
+      if (!lefthandside) {
+        if (!containsVariableSet()) {
+//          reportSyntaxError("The local variable " + new String(scanner.getCurrentIdentifierSource())
+//              + " may not have been initialized");
+          problemReporter.uninitializedLocalVariable(new String(scanner.getCurrentIdentifierSource()),scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
+              referenceContext, compilationUnit.compilationResult);
+        }
+      } else {
+        addVariableSet();
+      }
       FieldReference ref = new FieldReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition());
       getNextToken();
       return ref;
@@ -3105,7 +3141,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       System.out.println("TRACE: object_property()");
     }
     if (token == TokenNameVariable || token == TokenNameDOLLAR) {
-      variable_without_objects();
+      variable_without_objects(false);
     } else {
       object_dim_list();
     }
@@ -3171,23 +3207,23 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
   }
 
   private void r_variable() {
-    variable();
+    variable(false);
   }
 
-  private void w_variable() {
-    variable();
+  private void w_variable(boolean lefthandside) {
+    variable(lefthandside);
   }
 
   private void rw_variable() {
-    variable();
+    variable(false);
   }
 
-  private Expression variable() {
+  private Expression variable(boolean lefthandside) {
     //    variable:
     //         base_variable_with_function_calls T_OBJECT_OPERATOR
     //                 object_property method_or_not variable_properties
     // | base_variable_with_function_calls
-    Expression ref = base_variable_with_function_calls();
+    Expression ref = base_variable_with_function_calls(lefthandside);
     if (token == TokenNameMINUS_GREATER) {
       ref = null;
       getNextToken();
@@ -3526,7 +3562,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
         throwSyntaxError("'(' expected after keyword 'empty'");
       }
       getNextToken();
-      variable();
+      variable(false);
       if (token != TokenNameRPAREN) {
         throwSyntaxError("')' expected after keyword 'empty'");
       }
@@ -3658,7 +3694,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
       throwSyntaxError("Variable expected after keyword 'isset'");
     }
     while (true) {
-      variable();
+      variable(false);
       if (token == TokenNameCOMMA) {
         getNextToken();
       } else {
@@ -3976,6 +4012,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
 
   HashMap fMethodVariables = null;
 
+  Stack fStackUnassigned = new Stack();
+
   //ast stack
   final static int AstStackIncrement = 100;
 
@@ -4343,8 +4381,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
         }
       }
       if (scanner.recordLineSeparator) {
-                                       compilationUnit.compilationResult.lineSeparatorPositions =
-         scanner.getLineEnds();
+        compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
       }
       // check placement anomalies against other kinds of brackets
       for (int kind = 0; kind < BracketKinds; kind++) {
@@ -4480,4 +4517,83 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
     //endPosition is just before the ;
 
   }
+
+  public final static String[] GLOBALS = {
+      "$this",
+      "$_COOKIE",
+      "$_ENV",
+      "$_FILES",
+      "$_GET",
+      "$GLOBALS",
+      "$_POST",
+      "$_REQUEST",
+      "$_SESSION",
+      "$_SERVER"
+  };
+  /**
+   * 
+   */
+  private void pushVariableSet() {
+    HashSet set =new HashSet();
+    for (int i = 0; i < GLOBALS.length; i++) {
+      set.add(GLOBALS[i]);
+    }
+    fStackUnassigned.push(set);
+  }
+  
+  /**
+   * Returns the <i>set of assigned variables </i> returns null if no Set is defined at the current scanner position
+   */
+  private HashSet peekVariableSet() {
+    if (!fStackUnassigned.isEmpty()) {
+      return (HashSet) fStackUnassigned.peek();
+    }
+    return null;
+  }
+
+  /**
+   * add the current identifier source to the <i>set of assigned variables </i>
+   * 
+   * @param set
+   */
+  private void addVariableSet(HashSet set) {
+    if (set != null) {
+      set.add(new String(scanner.getCurrentTokenSource()));
+    }
+  }
+
+  /**
+   * add the current identifier source to the <i>set of assigned variables </i>
+   *  
+   */
+  private void addVariableSet() {
+    HashSet set = peekVariableSet();
+    if (set != null) {
+      set.add(new String(scanner.getCurrentTokenSource()));
+    }
+  }
+
+  /**
+   * add the current identifier source to the <i>set of assigned variables </i>
+   *  
+   */
+  private void addVariableSet(char[] token) {
+    HashSet set = peekVariableSet();
+    if (set != null) {
+      set.add(new String(token));
+    }
+  }
+
+  /**
+   * check if the current identifier source is in the <i>set of assigned variables </i> Returns true, if no set is defined for the
+   * current scanner position
+   *  
+   */
+  private boolean containsVariableSet() {
+    HashSet set = peekVariableSet();
+    if (set != null) {
+      return set.contains(new String(scanner.getCurrentTokenSource()));
+    }
+    return true;
+  }
 }
\ No newline at end of file