bugfix 1427544, http://sourceforge.net/tracker/?func=detail&atid=484801&aid=1427544...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
index 1a3da1e..c15c2de 100644 (file)
@@ -11,6 +11,11 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IType;
+import net.sourceforge.phpdt.core.JavaCore;
+import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.core.compiler.CharOperation;
 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
@@ -428,8 +433,13 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                if (branchStatement && statement != null) {
                                        // reportSyntaxError("Unreachable code", statement.sourceStart,
                                        // statement.sourceEnd);
-                                       problemReporter.unreachableCode(new String(scanner.getCurrentIdentifierSource()), statement.sourceStart,
+                                       if (! (statement instanceof BreakStatement)) {
+                                               /* don't give an error for break statement following return statement
+                                               Technically it's unreachable code, but in switch-case it's recommended to
+                                               avoid accidental fall-through later when editing the code */
+                                               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)
@@ -456,10 +466,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                }
                                                if (token == TokenNameif || token == TokenNameswitch || token == TokenNamefor || token == TokenNamewhile
                                                                || token == TokenNamedo || token == TokenNameforeach || token == TokenNamecontinue || token == TokenNamebreak
-                                                               || token == TokenNamereturn || token == TokenNameexit || token == TokenNameecho || token == TokenNameglobal
-                                                               || token == TokenNamestatic || token == TokenNameunset || token == TokenNamefunction || token == TokenNamedeclare
-                                                               || token == TokenNametry || token == TokenNamecatch || token == TokenNamethrow || token == TokenNamefinal
-                                                               || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
+                                                               || token == TokenNamereturn || token == TokenNameexit || token == TokenNameecho || token == TokenNameECHO_INVISIBLE
+                                                               || token == TokenNameglobal || token == TokenNamestatic || token == TokenNameunset || token == TokenNamefunction
+                                                               || token == TokenNamedeclare || token == TokenNametry || token == TokenNamecatch || token == TokenNamethrow
+                                                               || token == TokenNamefinal || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
                                                        break;
                                                }
                                                // System.out.println(scanner.toStringAction(token));
@@ -745,26 +755,32 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                        if (token == TokenNameSEMICOLON) {
                                getNextToken();
                        } else {
-                               if (token != TokenNameINLINE_HTML ) {
+                               if (token != TokenNameINLINE_HTML) {
                                        throwSyntaxError("';' expected after 'echo' statement.");
                                }
                                getNextToken();
                        }
                        return statement;
-               } else if (token == TokenNameINLINE_HTML) {
-//                     if (scanner.phpExpressionTag) {
-//                             // start of <?= ... ?> block
-//                             getNextToken();
-//                             expr();
-//                             if (token == TokenNameSEMICOLON) {
-//                                     getNextToken();
-//                             }
-//                             if (token != TokenNameINLINE_HTML) {
-//                                     throwSyntaxError("Missing '?>' for open PHP expression block ('<?=').");
-//                             }
-//                     } else {
+               } else if (token == TokenNameECHO_INVISIBLE) {
+                       // 0-length token directly after PHP short tag &lt;?=
+                       getNextToken();
+                       expressionList();
+                       if (token == TokenNameSEMICOLON) {
                                getNextToken();
-//                     }
+                               // if (token != TokenNameINLINE_HTML) {
+                               // // TODO should this become a configurable warning?
+                               // reportSyntaxError("Probably '?>' expected after PHP short tag
+                               // expression (only the first expression will be echoed).");
+                               // }
+                       } else {
+                               if (token != TokenNameINLINE_HTML) {
+                                       throwSyntaxError("';' expected after PHP short tag '<?=' expression.");
+                               }
+                               getNextToken();
+                       }
+                       return statement;
+               } else if (token == TokenNameINLINE_HTML) {
+                       getNextToken();
                        return statement;
                } else if (token == TokenNameglobal) {
                        getNextToken();
@@ -1264,7 +1280,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                // | T_EXTENDS interface_list
                if (token == TokenNameextends) {
                        getNextToken();
-                       interface_list();
+                       class_list(typeDecl);
                }
        }
 
@@ -1273,11 +1289,37 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                // | T_IMPLEMENTS interface_list
                if (token == TokenNameimplements) {
                        getNextToken();
-                       interface_list();
+                       interface_list(typeDecl);
                }
        }
 
-       private void interface_list() {
+       private void class_list(TypeDeclaration typeDecl) {
+               // class_list:
+               // fully_qualified_class_name
+               do {
+                       if (token == TokenNameIdentifier) {
+                               char[] ident = scanner.getCurrentIdentifierSource();
+                               // TODO make this code working better:
+                               // SingleTypeReference ref = ParserUtil.getTypeReference(scanner,
+                               // includesList, ident);
+                               // if (ref != null) {
+                               // typeDecl.superclass = ref;
+                               // }
+                               getNextToken();
+                       } else {
+                               throwSyntaxError("Classname expected after keyword 'extends'.");
+                       }
+                       if (token == TokenNameCOMMA) {
+                               reportSyntaxError("No multiple inheritence allowed. Expected token 'implements' or '{'.");
+                               getNextToken();
+                               continue;
+                       } else {
+                               break;
+                       }
+               } while (true);
+       }
+
+       private void interface_list(TypeDeclaration typeDecl) {
                // interface_list:
                // fully_qualified_class_name
                // | interface_list ',' fully_qualified_class_name
@@ -1285,7 +1327,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                        if (token == TokenNameIdentifier) {
                                getNextToken();
                        } else {
-                               throwSyntaxError("Interface name expected after keyword 'implements'.");
+                               throwSyntaxError("Interfacename expected after keyword 'implements'.");
                        }
                        if (token != TokenNameCOMMA) {
                                return;
@@ -1654,10 +1696,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                // | non_empty_parameter_list ',' optional_class_type T_VARIABLE '='
                // static_scalar
                char[] typeIdentifier = null;
-               if (token == TokenNameIdentifier || token == TokenNameVariable || token == TokenNameAND) {
+               if (token == TokenNameIdentifier || token == TokenNamearray || token == TokenNameVariable || token == TokenNameAND) {
                        HashSet set = peekVariableSet();
                        while (true) {
-                               if (token == TokenNameIdentifier) {
+                               if (token == TokenNameIdentifier || token == TokenNamearray) {// feature req. #1254275
                                        typeIdentifier = scanner.getCurrentIdentifierSource();
                                        getNextToken();
                                }
@@ -1737,6 +1779,11 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                expr(); // constant();
                                if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
                                        getNextToken();
+                                       if (token == TokenNameRBRACE) {
+                                               // empty case; assumes that the '}' token belongs to the wrapping
+                                               // switch statement - #1371992
+                                               break;
+                                       }
                                        if (token == TokenNamecase || token == TokenNamedefault) {
                                                // empty case statement ?
                                                continue;
@@ -1764,7 +1811,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
                                        getNextToken();
                                        if (token == TokenNameRBRACE) {
-                                               // empty default case
+                                               // empty default case; ; assumes that the '}' token belongs to the
+                                               // wrapping switch statement - #1371992
                                                break;
                                        }
                                        if (token != TokenNamecase) {
@@ -2160,11 +2208,11 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                if (Scanner.TRACE) {
                        System.out.println("TRACE: expr()");
                }
-               return expr_without_variable(true);
+               return expr_without_variable(true,null);
                // }
        }
 
-       private Expression expr_without_variable(boolean only_variable) {
+       private Expression expr_without_variable(boolean only_variable, UninitializedVariableHandler initHandler) {
                int exprSourceStart = scanner.getCurrentTokenStartPosition();
                int exprSourceEnd = scanner.getCurrentTokenEndPosition();
                Expression expression = new Expression();
@@ -2514,8 +2562,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                        && token != TokenNameLEFT_SHIFT_EQUAL) {
                                                FieldReference ref = (FieldReference) lhs;
                                                if (!containsVariableSet(ref.token)) {
-                                                       problemReporter.uninitializedLocalVariable(new String(ref.token), ref.sourceStart(), ref.sourceEnd(),
+                                                       if (null==initHandler || initHandler.reportError()) {
+                                                               problemReporter.uninitializedLocalVariable(new String(ref.token), ref.sourceStart, ref.sourceEnd,
                                                                        referenceContext, compilationUnit.compilationResult);
+                                                       }
                                                        addVariableSet(ref.token);
                                                }
                                        }
@@ -2539,7 +2589,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                                        // example:
                                                                        // $var = & new Object();
                                                                        if (fMethodVariables != null) {
-                                                                               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
+                                                                               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
                                                                                lhsInfo.reference = classRef;
                                                                                lhsInfo.typeIdentifier = classRef.token;
                                                                                fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
@@ -2555,7 +2605,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                                if (fMethodVariables != null) {
                                                                        VariableInfo rhsInfo = (VariableInfo) fMethodVariables.get(((FieldReference) rhs).token);
                                                                        if (rhsInfo != null && rhsInfo.reference != null) {
-                                                                               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
+                                                                               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
                                                                                lhsInfo.reference = rhsInfo.reference;
                                                                                lhsInfo.typeIdentifier = rhsInfo.typeIdentifier;
                                                                                fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
@@ -2573,7 +2623,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                                if (fMethodVariables != null) {
                                                                        VariableInfo rhsInfo = (VariableInfo) fMethodVariables.get(((FieldReference) rhs).token);
                                                                        if (rhsInfo != null && rhsInfo.reference != null) {
-                                                                               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
+                                                                               VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
                                                                                lhsInfo.reference = rhsInfo.reference;
                                                                                lhsInfo.typeIdentifier = rhsInfo.typeIdentifier;
                                                                                fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
@@ -2584,7 +2634,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                                // example:
                                                                // $var = new Object();
                                                                if (fMethodVariables != null) {
-                                                                       VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
+                                                                       VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
                                                                        lhsInfo.reference = (SingleTypeReference) rhs;
                                                                        lhsInfo.typeIdentifier = ((SingleTypeReference) rhs).token;
                                                                        fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
@@ -2595,7 +2645,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                        }
                                        if (rememberedVar == false && lhs != null && lhs instanceof FieldReference) {
                                                if (fMethodVariables != null) {
-                                                       VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart());
+                                                       VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
                                                        fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
                                                }
                                        }
@@ -2848,6 +2898,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                        variable(true, false);
                } else if (token == TokenNameDOLLAR) {
                        variable(false, false);
+               } else if (token == TokenNameIdentifier) {
+                       identifier(true, true);
                } else {
                        if (token == TokenNamelist) {
                                getNextToken();
@@ -3022,12 +3074,16 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                return ref;
        }
 
+       private void non_empty_function_call_parameter_list() {
+               this.non_empty_function_call_parameter_list(null);
+       }
+
        // private void function_call_parameter_list() {
        // function_call_parameter_list:
        // non_empty_function_call_parameter_list { $$ = $1; }
        // | /* empty */
        // }
-       private void non_empty_function_call_parameter_list() {
+       private void non_empty_function_call_parameter_list(String functionName) {
                // non_empty_function_call_parameter_list:
                // expr_without_variable
                // | variable
@@ -3038,7 +3094,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                if (Scanner.TRACE) {
                        System.out.println("TRACE: non_empty_function_call_parameter_list()");
                }
+               UninitializedVariableHandler initHandler = new UninitializedVariableHandler();
+               initHandler.setFunctionName(functionName);
                while (true) {
+                       initHandler.incrementArgumentCount();
                        if (token == TokenNameAND) {
                                getNextToken();
                                w_variable(true);
@@ -3048,7 +3107,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                // || token == TokenNameDOLLAR) {
                                // variable();
                                // } else {
-                               expr_without_variable(true);
+                               expr_without_variable(true, initHandler);
                                // }
                        }
                        if (token != TokenNameCOMMA) {
@@ -3136,11 +3195,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                }
                                getNextToken();
                        } else if (token == TokenNameLBRACKET) {
-                               if (ref != null && ref instanceof FieldReference) {
-                                       FieldReference fref = (FieldReference) ref;
-                                       addVariableSet(fref.token);
-                               }
-                               ref = null;
+                               // To remove "ref = null;" here, is probably better than the patch
+                               // commented in #1368081 - axelcl
                                getNextToken();
                                if (token != TokenNameRBRACKET) {
                                        expr();
@@ -3420,14 +3476,14 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                getNextToken();
                                ref = null;
                        } else {
-                               non_empty_function_call_parameter_list();
+                               String functionName;
+                               if (ident == null) {
+                                       functionName = new String(" ");
+                               } else {
+                                       functionName = new String(ident);
+                               }
+                               non_empty_function_call_parameter_list(functionName);
                                if (token != TokenNameRPAREN) {
-                                       String functionName;
-                                       if (ident == null) {
-                                               functionName = new String(" ");
-                                       } else {
-                                               functionName = new String(ident);
-                                       }
                                        throwSyntaxError("')' expected in function call (" + functionName + ").");
                                }
                                getNextToken();
@@ -3865,8 +3921,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI
                                                        String ext = file.getRawLocation().getFileExtension();
                                                        int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
 
+                                                       IFile f = PHPFileUtil.createFile(path, project);
+
                                                        impt.tokens = CharOperation.splitOn('/', filePath.toCharArray(), 0, filePath.length() - fileExtensionLength);
-                                                       impt.setFile(PHPFileUtil.createFile(path, project));
+                                                       impt.setFile(f);
                                                } catch (Exception e) {
                                                        // the file is outside of the workspace
                                                }