From d8a39229d8f794f3c7292728930bde1c1010cf7a Mon Sep 17 00:00:00 2001 From: axelcl Date: Sun, 17 Apr 2005 21:30:28 +0000 Subject: [PATCH] Added error "Unreachable code" for if statements --- .../phpdt/internal/compiler/parser/Parser.java | 406 ++++++++++++-------- .../internal/compiler/ast/IfStatement.java | 7 +- .../phpeditor/php/PHPAutoIndentStrategy.java | 7 + 3 files changed, 259 insertions(+), 161 deletions(-) diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java index 0bfc22c..4777170 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java @@ -26,6 +26,7 @@ import net.sourceforge.phpeclipse.internal.compiler.ast.AND_AND_Expression; import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode; import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration; import net.sourceforge.phpeclipse.internal.compiler.ast.BinaryExpression; +import net.sourceforge.phpeclipse.internal.compiler.ast.Block; import net.sourceforge.phpeclipse.internal.compiler.ast.BreakStatement; import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration; import net.sourceforge.phpeclipse.internal.compiler.ast.ConditionalExpression; @@ -460,19 +461,18 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI return compilationUnit; } -// private boolean isVariable() { -// return token == TokenNameVariable; // || token == TokenNamethis; -// } - - private void statementList() { + private Block statementList() { boolean branchStatement = false; Statement statement; int sourceStart; int sourceEnd; + int blockStart = scanner.getCurrentTokenStartPosition(); + ArrayList blockStatements = new ArrayList(); do { try { sourceStart = scanner.getCurrentTokenStartPosition(); - statement = statement(TokenNameEOF); + statement = statement(); + blockStatements.add(statement); if (branchStatement) { sourceEnd = scanner.getCurrentTokenEndPosition(); reportSyntaxError("Unreachable code", sourceStart, sourceEnd); @@ -481,12 +481,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor) || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch) || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) { - return; - } - branchStatement = false; - if (statement instanceof ReturnStatement ||statement instanceof ContinueStatement || statement instanceof BreakStatement) { - branchStatement = true; + return createBlock(blockStart, blockStatements); } + branchStatement = checkUnreachableStatements(statement); +// return createBlock(blockStart, blockStatements); } catch (SyntaxError sytaxErr1) { // if an error occured, // try to find keywords @@ -501,7 +499,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor) || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch) || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) { - return; + return createBlock(blockStart, blockStatements); } if (token == TokenNameif || token == TokenNameswitch || token == TokenNamefor || token == TokenNamewhile || token == TokenNamedo || token == TokenNameforeach || token == TokenNamecontinue || token == TokenNamebreak @@ -525,6 +523,33 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } while (true); } + /** + * @param statement + * @return + */ + private boolean checkUnreachableStatements(Statement statement) { + boolean branchStatement = false; + if (statement instanceof ReturnStatement || statement instanceof ContinueStatement || statement instanceof BreakStatement) { + branchStatement = true; + } else if (statement instanceof IfStatement && ((IfStatement)statement).checkUnreachable) { + branchStatement = true; + } + return branchStatement; + } + + /** + * @param blockStart + * @param blockStatements + * @return + */ + private Block createBlock(int blockStart, ArrayList blockStatements) { + int blockEnd = scanner.getCurrentTokenEndPosition(); + Block b = Block.EmptyWith(blockStart, blockEnd); + b.statements = new Statement[blockStatements.size()]; + blockStatements.toArray(b.statements); + return b; + } + private void functionBody(MethodDeclaration methodDecl) { // '{' [statement-list] '}' if (token == TokenNameLBRACE) { @@ -543,12 +568,14 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } } - private Statement statement(int previousToken) { + private Statement statement() { Statement statement = null; Expression expression; int sourceStart = scanner.getCurrentTokenStartPosition(); int sourceEnd; if (token == TokenNameif) { + // T_IF '(' expr ')' statement elseif_list else_single + // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' getNextToken(); if (token == TokenNameLPAREN) { getNextToken(); @@ -561,8 +588,15 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } else { throwSyntaxError("')' expected after 'if' condition."); } - ifStatement(); - return new IfStatement(expression, statement, sourceStart, scanner.getCurrentTokenEndPosition()); + // create basic IfStatement + IfStatement ifStatement = new IfStatement(expression, null, null, sourceStart, -1); + if (token == TokenNameCOLON) { + getNextToken(); + ifStatementColon(ifStatement); + } else { + ifStatement(ifStatement); + } + return ifStatement; } else if (token == TokenNameswitch) { getNextToken(); if (token == TokenNameLPAREN) { @@ -645,7 +679,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI throwSyntaxError("'}' expected after 'do' keyword."); } } else { - statement(TokenNameEOF); + statement(); } if (token == TokenNamewhile) { getNextToken(); @@ -715,7 +749,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); } - return new BreakStatement(null,sourceStart, sourceEnd); + return new BreakStatement(null, sourceStart, sourceEnd); } else if (token == TokenNamecontinue) { expression = null; getNextToken(); @@ -732,7 +766,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); } - return new ContinueStatement(null,sourceStart, sourceEnd); + return new ContinueStatement(null, sourceStart, sourceEnd); } else if (token == TokenNamereturn) { expression = null; getNextToken(); @@ -749,7 +783,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); } - return new ReturnStatement(expression,sourceStart, sourceEnd); + return new ReturnStatement(expression, sourceStart, sourceEnd); } else if (token == TokenNameecho) { getNextToken(); expressionList(); @@ -924,7 +958,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } else if (token == TokenNameLBRACE) { getNextToken(); if (token != TokenNameRBRACE) { - statementList(); + statement = statementList(); } if (token == TokenNameRBRACE) { getNextToken(); @@ -971,7 +1005,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameRPAREN); + statement(); } } @@ -1764,162 +1798,214 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } while (token == TokenNamecase || token == TokenNamedefault); } - // public void labeledStatement() { - // if (token == TokenNamecase) { - // getNextToken(); - // constant(); - // if (token == TokenNameDDOT) { - // getNextToken(); - // statement(); - // } else { - // throwSyntaxError("':' character after 'case' constant expected."); - // } - // return; - // } else if (token == TokenNamedefault) { - // getNextToken(); - // if (token == TokenNameDDOT) { - // getNextToken(); - // statement(); - // } else { - // throwSyntaxError("':' character after 'default' expected."); - // } - // return; - // } - // } - // public void expressionStatement() { - // } - // private void inclusionStatement() { - // } - // public void compoundStatement() { - // } - // public void selectionStatement() { - // } - // - // public void iterationStatement() { - // } - // - // public void jumpStatement() { - // } - // - // public void outputStatement() { - // } - // - // public void scopeStatement() { - // } - // - // public void flowStatement() { - // } - // - // public void definitionStatement() { - // } - private void ifStatement() { - // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';' - if (token == TokenNameCOLON) { - getNextToken(); - if (token != TokenNameendif) { - statementList(); - switch (token) { - case TokenNameelse: - getNextToken(); - if (token == TokenNameCOLON) { - getNextToken(); - if (token != TokenNameendif) { - statementList(); - } - } else { - if (token == TokenNameif) { //'else if' - getNextToken(); - elseifStatementList(); - } else { - throwSyntaxError("':' expected after 'else'."); - } - } - break; - case TokenNameelseif: - getNextToken(); - elseifStatementList(); - break; - } - } - if (token != TokenNameendif) { - throwSyntaxError("'endif' expected."); - } + private void ifStatementColon(IfStatement iState) { + // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' + Block b = inner_statement_list(); + iState.thenStatement = b; + checkUnreachable(iState, b); + if (token == TokenNameelseif) { + new_elseif_list(iState); + } + new_else_single(iState); + if (token != TokenNameendif) { + throwSyntaxError("'endif' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + reportSyntaxError("';' expected after if-statement."); + iState.sourceEnd = scanner.getCurrentTokenStartPosition(); + } else { + iState.sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); - if (token != TokenNameSEMICOLON) { - throwSyntaxError("';' expected after if-statement."); - } + } + } + + private void ifStatement(IfStatement iState) { + // T_IF '(' expr ')' statement elseif_list else_single + Statement s = statement(); + iState.thenStatement = s; + checkUnreachable(iState, s); + if (token == TokenNameelseif) { + elseif_list(iState); + } + else_single(iState); + } + + private void elseif_list(IfStatement iState) { + // /* empty */ + //| elseif_list T_ELSEIF '(' expr ')' statement + ArrayList conditionList = new ArrayList(); + ArrayList statementList = new ArrayList(); + Expression e; + Statement s; + while (token == TokenNameelseif) { getNextToken(); - } else { - // statement [else-statement] - statement(TokenNameEOF); - if (token == TokenNameelseif) { + if (token == TokenNameLPAREN) { getNextToken(); - if (token == TokenNameLPAREN) { - getNextToken(); - } else { - throwSyntaxError("'(' expected after 'elseif' keyword."); - } - expr(); - if (token == TokenNameRPAREN) { - getNextToken(); - } else { - throwSyntaxError("')' expected after 'elseif' condition."); - } - ifStatement(); - } else if (token == TokenNameelse) { + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + e = expr(); + conditionList.add(e); + if (token == TokenNameRPAREN) { getNextToken(); - statement(TokenNameEOF); + } else { + throwSyntaxError("')' expected after 'elseif' condition."); } + s = statement(); + statementList.add(s); + checkUnreachable(iState, s); } + iState.elseifConditions = new Expression[conditionList.size()]; + iState.elseifStatements = new Statement[statementList.size()]; + conditionList.toArray(iState.elseifConditions); + statementList.toArray(iState.elseifStatements); } - private void elseifStatementList() { - do { - elseifStatement(); - switch (token) { - case TokenNameelse: + private void new_elseif_list(IfStatement iState) { + // /* empty */ + //| new_elseif_list T_ELSEIF '(' expr ')' ':' inner_statement_list + ArrayList conditionList = new ArrayList(); + ArrayList statementList = new ArrayList(); + Expression e; + Block b; + while (token == TokenNameelseif) { + getNextToken(); + if (token == TokenNameLPAREN) { getNextToken(); - if (token == TokenNameCOLON) { - getNextToken(); - if (token != TokenNameendif) { - statementList(); - } - return; - } else { - if (token == TokenNameif) { //'else if' - getNextToken(); - } else { - throwSyntaxError("':' expected after 'else'."); - } - } - break; - case TokenNameelseif: + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + e = expr(); + conditionList.add(e); + if (token == TokenNameRPAREN) { getNextToken(); - break; - default: - return; + } else { + throwSyntaxError("')' expected after 'elseif' condition."); } - } while (true); + if (token == TokenNameCOLON) { + getNextToken(); + } else { + throwSyntaxError("':' expected after 'elseif' keyword."); + } + b = inner_statement_list(); + statementList.add(b); + checkUnreachable(iState, b); + } + iState.elseifConditions = new Expression[conditionList.size()]; + iState.elseifStatements = new Statement[statementList.size()]; + conditionList.toArray(iState.elseifConditions); + statementList.toArray(iState.elseifStatements); } - private void elseifStatement() { - if (token == TokenNameLPAREN) { + private void else_single(IfStatement iState) { + // /* empty */ + // T_ELSE statement + if (token == TokenNameelse) { getNextToken(); - expr(); - if (token != TokenNameRPAREN) { - throwSyntaxError("')' expected in else-if-statement."); - } + Statement s = statement(); + iState.elseStatement = s; + checkUnreachable(iState, s); + } else { + iState.checkUnreachable = false; + } + iState.sourceEnd = scanner.getCurrentTokenStartPosition(); + } + + private void new_else_single(IfStatement iState) { + // /* empty */ + //| T_ELSE ':' inner_statement_list + if (token == TokenNameelse) { getNextToken(); - if (token != TokenNameCOLON) { - throwSyntaxError("':' expected in else-if-statement."); + if (token == TokenNameCOLON) { + getNextToken(); + } else { + throwSyntaxError("':' expected after 'else' keyword."); } - getNextToken(); - if (token != TokenNameendif) { - statementList(); + Block b = inner_statement_list(); + iState.elseStatement = b; + checkUnreachable(iState, b); + } else { + iState.checkUnreachable = false; + } + } + + private Block inner_statement_list() { + // inner_statement_list inner_statement + // /* empty */ + return statementList(); + } + + /** + * @param iState + * @param b + */ + private void checkUnreachable(IfStatement iState, Statement s) { + if (s instanceof Block) { + Block b = (Block) s; + if (b.statements == null || b.statements.length == 0) { + iState.checkUnreachable = false; + } else { + int off = b.statements.length - 1; + if (!(b.statements[off] instanceof ReturnStatement) && !(b.statements[off] instanceof ContinueStatement) + && !(b.statements[off] instanceof BreakStatement)) { + iState.checkUnreachable = false; + } + } + } else { + if (!(s instanceof ReturnStatement) && !(s instanceof ContinueStatement) && !(s instanceof BreakStatement)) { + iState.checkUnreachable = false; } } } + // private void elseifStatementList() { + // do { + // elseifStatement(); + // switch (token) { + // case TokenNameelse: + // getNextToken(); + // if (token == TokenNameCOLON) { + // getNextToken(); + // if (token != TokenNameendif) { + // statementList(); + // } + // return; + // } else { + // if (token == TokenNameif) { //'else if' + // getNextToken(); + // } else { + // throwSyntaxError("':' expected after 'else'."); + // } + // } + // break; + // case TokenNameelseif: + // getNextToken(); + // break; + // default: + // return; + // } + // } while (true); + // } + + // private void elseifStatement() { + // if (token == TokenNameLPAREN) { + // getNextToken(); + // expr(); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected in else-if-statement."); + // } + // getNextToken(); + // if (token != TokenNameCOLON) { + // throwSyntaxError("':' expected in else-if-statement."); + // } + // getNextToken(); + // if (token != TokenNameendif) { + // statementList(); + // } + // } + // } + private void switchStatement() { if (token == TokenNameCOLON) { // ':' [labeled-statement-list] 'endswitch' ';' @@ -1962,7 +2048,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameEOF); + statement(); } } @@ -1980,7 +2066,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameEOF); + statement(); } } @@ -1997,7 +2083,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameEOF); + statement(); } } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/IfStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/IfStatement.java index d0257f3..d76577b 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/IfStatement.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/IfStatement.java @@ -25,8 +25,11 @@ public class IfStatement extends Statement { public Expression condition; public Statement thenStatement; public Statement elseStatement; - + public Expression[] elseifConditions; + public Statement[] elseifStatements; + public boolean checkUnreachable; boolean thenExit; + // for local variables table attributes int thenInitStateIndex = -1; @@ -43,6 +46,7 @@ public class IfStatement extends Statement { this.thenStatement = thenStatement; sourceStart = s; sourceEnd = e; + checkUnreachable = true; } public IfStatement( @@ -57,6 +61,7 @@ public class IfStatement extends Statement { this.elseStatement = elseStatement; sourceEnd = e; sourceStart = s; + checkUnreachable = true; } public FlowInfo analyseCode( diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java index 042fe11..5647b5b 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java @@ -221,10 +221,17 @@ public class PHPAutoIndentStrategy extends DefaultAutoIndentStrategy { } else { int start= document.getLineOffset(line); int whiteend= findEndOfWhiteSpace(document, start, command.offset); + int offset = -1; +// if (command.offset > 0 && command.offset < docLength && document.getChar(command.offset-1) == '{') { +// offset = command.offset; +// } buf.append(document.get(start, whiteend - start)); if (getBracketCount(document, start, command.offset, true) > 0) { buf.append('\t'); } +// if (offset >= 0) { +// buf.append('}'); +// } } command.text= buf.toString(); -- 1.7.1