/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser.statements;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.IStatement;
import gw.lang.parser.expressions.IIdentifierExpression;
import gw.lang.parser.statements.ICatchClause;
import gw.lang.parser.statements.IIfStatement;
import gw.lang.parser.statements.ILoopStatement;
import gw.lang.parser.statements.ITerminalStatement;
import gw.lang.parser.statements.ITryCatchFinallyStatement;
import java.util.List;
/**
*/
class AssignmentOrReference {
private IParsedElement _stmt;
private ITerminalStatement _terminal;
private VarInitializationVerifier.AssignedState _localState;
private boolean _bBad;
private boolean _bInLoop;
private boolean _bReference;
AssignmentOrReference( IStatement stmt, List<AssignmentOrReference> assignments, VarInitializationVerifier.AssignedState localState ) {
_stmt = stmt;
_localState = localState;
determineBad( assignments, false );
}
AssignmentOrReference( IIdentifierExpression idExpr, List<AssignmentOrReference> assignments, VarInitializationVerifier.AssignedState localState ) {
_stmt = idExpr;
_bReference = true;
_localState = localState;
determineBad( assignments, false );
}
IParsedElement getStmt() {
return _stmt;
}
ITerminalStatement getTerminal() {
return _terminal;
}
void setTerminal( ITerminalStatement terminal ) {
_terminal = terminal;
}
VarInitializationVerifier.AssignedState getLocalState() {
return _localState;
}
boolean isBad() {
return _bBad;
}
private void setBad( boolean bBad ) {
_bBad = bBad;
}
boolean isReference() {
return _bReference;
}
boolean isInLoop() {
return _bInLoop;
}
void determineBad( List<AssignmentOrReference> assignments, boolean bInLoop ) {
if( isBad() ) {
// Already bad
return;
}
if( bInLoop && isReference() ) {
// This is intended for re-determining the badness of Assignments inside a loop
return;
}
outer:
for( AssignmentOrReference csr : assignments ) {
if( csr.isReference() ) {
continue;
}
if( csr.getTerminal() != null ) {
// If the terminal's ctx contains this assignment, the csr is irrelevant, move to next
switch( csr.getTerminal().getTerminalType() ) {
case ReturnOrThrow:
case ForeverLoop:
continue;
case Break:
{
IParsedElement pe = csr.getTerminal();
while( pe != null ) {
if( pe instanceof ILoopStatement ||
pe instanceof SwitchStatement ) {
if( VarInitializationVerifier.isStatementContainedIn( getStmt(), pe ) ) {
continue outer;
}
}
pe = pe.getParent();
}
break;
}
case Continue:
{
IParsedElement pe = csr.getTerminal();
while( pe != null ) {
if( pe instanceof ILoopStatement ) {
if( VarInitializationVerifier.isStatementContainedIn( getStmt(), pe ) ) {
continue outer;
}
}
pe = pe.getParent();
}
break;
}
}
}
else {
if( separatedByIfElse( csr.getStmt(), getStmt() ) ) {
continue;
}
if( separatedByCatchClauses( csr.getStmt(), getStmt() ) ) {
continue;
}
}
// The csr assignment may conflict with this one, so it's bad
setBad( true );
// This is only to indicate this is bad because it's in a loop, to provide a better error msg
_bInLoop = bInLoop;
break;
}
if( isReference() ) {
setBad( !isBad() || getLocalState() != VarInitializationVerifier.AssignedState.Fully );
}
}
private boolean separatedByIfElse( IParsedElement stmt1, IParsedElement stmt2 ) {
return _separatedByIfElse( stmt1, stmt1, stmt2 );
}
private boolean _separatedByIfElse( IParsedElement origStmt, IParsedElement stmt1, IParsedElement stmt2 ) {
if( stmt1 == null ) {
return false;
}
if( stmt1 instanceof IIfStatement &&
VarInitializationVerifier.isStatementContainedIn( origStmt, ((IIfStatement)stmt1).getStatement() ) ) {
IStatement elseStmt = ((IIfStatement)stmt1).getElseStatement();
if( elseStmt != null && VarInitializationVerifier.isStatementContainedIn( stmt2, elseStmt ) ) {
return true;
}
}
return _separatedByIfElse( origStmt, stmt1.getParent(), stmt2 );
}
private boolean separatedByCatchClauses( IParsedElement stmt1, IParsedElement stmt2 ) {
if( stmt1 == null ) {
return false;
}
if( stmt1 instanceof ICatchClause ) {
IParsedElement parent = stmt1.getParent();
if( parent instanceof ITryCatchFinallyStatement ) {
for( ICatchClause catchClause: ((ITryCatchFinallyStatement)parent).getCatchStatements() ) {
if( catchClause != stmt1 && VarInitializationVerifier.isStatementContainedIn( stmt2, catchClause ) ) {
return true;
}
}
}
}
return separatedByCatchClauses( stmt1.getParent(), stmt2 );
}
}