use of org.codehaus.groovy.ast.stmt.EmptyStatement in project groovy by apache.
the class AntlrParserPlugin method tryStatement.
protected Statement tryStatement(AST tryStatementNode) {
AST tryNode = tryStatementNode.getFirstChild();
Statement tryStatement = statement(tryNode);
Statement finallyStatement = EmptyStatement.INSTANCE;
AST node = tryNode.getNextSibling();
// let's do the catch nodes
List<CatchStatement> catches = new ArrayList<CatchStatement>();
for (; node != null && isType(LITERAL_catch, node); node = node.getNextSibling()) {
final List<CatchStatement> catchStatements = catchStatement(node);
catches.addAll(catchStatements);
}
if (isType(LITERAL_finally, node)) {
finallyStatement = statement(node);
node = node.getNextSibling();
}
if (finallyStatement instanceof EmptyStatement && catches.isEmpty()) {
throw new ASTRuntimeException(tryStatementNode, "A try statement must have at least one catch or finally block.");
}
TryCatchStatement tryCatchStatement = new TryCatchStatement(tryStatement, finallyStatement);
configureAST(tryCatchStatement, tryStatementNode);
for (CatchStatement statement : catches) {
tryCatchStatement.addCatch(statement);
}
return tryCatchStatement;
}
use of org.codehaus.groovy.ast.stmt.EmptyStatement in project groovy-core by groovy.
the class FinalVariableAnalyzer method visitTryCatchFinally.
@Override
public void visitTryCatchFinally(final TryCatchStatement statement) {
visitStatement(statement);
Map<Variable, VariableState> beforeTryCatch = new HashMap<Variable, VariableState>(getState());
statement.getTryStatement().visit(this);
for (CatchStatement catchStatement : statement.getCatchStatements()) {
catchStatement.visit(this);
}
Statement finallyStatement = statement.getFinallyStatement();
// we need to recall which final variables are unassigned so cloning the current state
Map<Variable, VariableState> afterTryCatchState = new HashMap<Variable, VariableState>(getState());
if (finallyStatement instanceof EmptyStatement) {
// dispatching to EmptyStatement will not call back visitor,
// must call our visitEmptyStatement explicitly
visitEmptyStatement((EmptyStatement) finallyStatement);
} else {
finallyStatement.visit(this);
}
// and now we must reset to uninitialized state variables which were only initialized during try/catch
Map<Variable, VariableState> afterFinally = new HashMap<Variable, VariableState>(getState());
for (Map.Entry<Variable, VariableState> entry : afterFinally.entrySet()) {
Variable var = entry.getKey();
VariableState afterFinallyState = entry.getValue();
VariableState beforeTryCatchState = beforeTryCatch.get(var);
if (afterFinallyState == VariableState.is_final && beforeTryCatchState != VariableState.is_final && afterTryCatchState.get(var) != beforeTryCatchState) {
getState().put(var, beforeTryCatchState == null ? VariableState.is_uninitialized : beforeTryCatchState);
}
}
}
use of org.codehaus.groovy.ast.stmt.EmptyStatement in project groovy by apache.
the class ReturnAdder method addReturnsIfNeeded.
private Statement addReturnsIfNeeded(final Statement statement, final VariableScope scope) {
if (statement instanceof ReturnStatement || statement instanceof ThrowStatement || statement instanceof EmptyStatement || statement instanceof BytecodeSequence) {
return statement;
}
if (statement == null) {
ReturnStatement returnStatement = new ReturnStatement(nullX());
listener.returnStatementAdded(returnStatement);
return returnStatement;
}
if (statement instanceof ExpressionStatement) {
Expression expression = ((ExpressionStatement) statement).getExpression();
ReturnStatement returnStatement = new ReturnStatement(expression);
returnStatement.copyStatementLabels(statement);
returnStatement.setSourcePosition(statement.getLineNumber() < 0 ? expression : statement);
listener.returnStatementAdded(returnStatement);
return returnStatement;
}
if (statement instanceof SynchronizedStatement) {
SynchronizedStatement syncStatement = (SynchronizedStatement) statement;
Statement code = addReturnsIfNeeded(syncStatement.getCode(), scope);
if (doAdd)
syncStatement.setCode(code);
return syncStatement;
}
if (statement instanceof IfStatement) {
IfStatement ifElseStatement = (IfStatement) statement;
Statement ifBlock = addReturnsIfNeeded(ifElseStatement.getIfBlock(), scope);
Statement elseBlock = addReturnsIfNeeded(ifElseStatement.getElseBlock(), scope);
if (doAdd) {
ifElseStatement.setIfBlock(ifBlock);
ifElseStatement.setElseBlock(elseBlock);
}
return ifElseStatement;
}
if (statement instanceof SwitchStatement) {
SwitchStatement switchStatement = (SwitchStatement) statement;
Statement defaultStatement = switchStatement.getDefaultStatement();
List<CaseStatement> caseStatements = switchStatement.getCaseStatements();
for (Iterator<CaseStatement> it = caseStatements.iterator(); it.hasNext(); ) {
CaseStatement caseStatement = it.next();
Statement code = adjustSwitchCaseCode(caseStatement.getCode(), scope, // GROOVY-9896: return if no default and last case lacks break
defaultStatement == EmptyStatement.INSTANCE && !it.hasNext());
if (doAdd)
caseStatement.setCode(code);
}
defaultStatement = adjustSwitchCaseCode(defaultStatement, scope, true);
if (doAdd)
switchStatement.setDefaultStatement(defaultStatement);
return switchStatement;
}
if (statement instanceof TryCatchStatement) {
TryCatchStatement tryCatchFinally = (TryCatchStatement) statement;
boolean[] missesReturn = new boolean[1];
new ReturnAdder(returnStatement -> missesReturn[0] = true).addReturnsIfNeeded(tryCatchFinally.getFinallyStatement(), scope);
boolean hasFinally = !(tryCatchFinally.getFinallyStatement() instanceof EmptyStatement);
// there is nothing to do
if (hasFinally && !missesReturn[0])
return tryCatchFinally;
// add returns to try and catch blocks
Statement tryStatement = addReturnsIfNeeded(tryCatchFinally.getTryStatement(), scope);
if (doAdd)
tryCatchFinally.setTryStatement(tryStatement);
for (CatchStatement catchStatement : tryCatchFinally.getCatchStatements()) {
Statement code = addReturnsIfNeeded(catchStatement.getCode(), scope);
if (doAdd)
catchStatement.setCode(code);
}
return tryCatchFinally;
}
if (statement instanceof BlockStatement) {
BlockStatement blockStatement = (BlockStatement) statement;
if (blockStatement.isEmpty()) {
ReturnStatement returnStatement = new ReturnStatement(nullX());
returnStatement.copyStatementLabels(blockStatement);
returnStatement.setSourcePosition(blockStatement);
listener.returnStatementAdded(returnStatement);
return returnStatement;
} else {
List<Statement> statements = blockStatement.getStatements();
int lastIndex = statements.size() - 1;
Statement last = addReturnsIfNeeded(statements.get(lastIndex), blockStatement.getVariableScope());
if (doAdd)
statements.set(lastIndex, last);
return blockStatement;
}
}
List<Statement> statements = new ArrayList<>(2);
statements.add(statement);
ReturnStatement returnStatement = new ReturnStatement(nullX());
listener.returnStatementAdded(returnStatement);
statements.add(returnStatement);
BlockStatement blockStatement = new BlockStatement(statements, new VariableScope(scope));
blockStatement.setSourcePosition(statement);
return blockStatement;
}
use of org.codehaus.groovy.ast.stmt.EmptyStatement in project groovy by apache.
the class FinalVariableAnalyzer method visitSwitch.
@Override
public void visitSwitch(SwitchStatement switchS) {
visitStatement(switchS);
switchS.getExpression().visit(this);
List<Statement> branches = new ArrayList<>(switchS.getCaseStatements());
if (!(switchS.getDefaultStatement() instanceof EmptyStatement)) {
branches.add(switchS.getDefaultStatement());
}
List<Map<Variable, VariableState>> afterStates = new ArrayList<>();
// collect after states
int lastIndex = branches.size() - 1;
for (int i = 0; i <= lastIndex; i++) {
pushState();
boolean done = false;
boolean returning = false;
for (int j = i; !done; j++) {
Statement branch = branches.get(j);
// default branch
Statement block = branch;
if (branch instanceof CaseStatement) {
CaseStatement caseS = (CaseStatement) branch;
block = caseS.getCode();
caseS.getExpression().visit(this);
}
block.visit(this);
done = j == lastIndex || !fallsThrough(block);
if (done) {
returning = returningBlock(block);
}
}
if (!returning) {
afterStates.add(getState());
}
popState();
}
if (afterStates.isEmpty()) {
return;
}
// merge branches
Map<Variable, VariableState> beforeState = getState();
Set<Variable> allVars = new HashSet<>(beforeState.keySet());
for (Map<Variable, VariableState> map : afterStates) {
allVars.addAll(map.keySet());
}
for (Variable var : allVars) {
VariableState beforeValue = beforeState.get(var);
if (beforeValue != null) {
final VariableState merged = afterStates.get(0).get(var);
if (merged != null) {
if (afterStates.stream().allMatch(state -> merged.equals(state.get(var)))) {
beforeState.put(var, merged);
} else {
VariableState different = beforeValue == VariableState.is_uninitialized ? VariableState.is_ambiguous : VariableState.is_var;
beforeState.put(var, different);
}
}
}
}
}
use of org.codehaus.groovy.ast.stmt.EmptyStatement in project groovy by apache.
the class FinalVariableAnalyzer method fallsThrough.
/**
* @return true if the block falls through, i.e. no break/return
*/
private boolean fallsThrough(Statement statement) {
if (statement instanceof EmptyStatement) {
return true;
}
if (statement instanceof ReturnStatement) {
// from ReturnAdder
return false;
}
// currently only possibility
BlockStatement block = (BlockStatement) statement;
if (block.getStatements().size() == 0) {
return true;
}
Statement last = DefaultGroovyMethods.last(block.getStatements());
boolean completesAbruptly = last instanceof ReturnStatement || last instanceof BreakStatement || last instanceof ThrowStatement || last instanceof ContinueStatement;
return !completesAbruptly;
}
Aggregations