int ControlFlowBuilder::before(ConstructRawPtr cp) { int ret = FunctionWalker::before(cp); if (ret == WalkContinue) { if (m_pass == 1) { if (StatementPtr s = dynamic_pointer_cast<Statement>(cp)) { Statement::KindOf stype = s->getKindOf(); switch (stype) { case Statement::KindOfFunctionStatement: case Statement::KindOfMethodStatement: case Statement::KindOfClassStatement: case Statement::KindOfInterfaceStatement: assert(false); break; case Statement::KindOfStaticStatement: addEdge(s, BeforeConstruct, s, AfterConstruct); break; case Statement::KindOfClassVariable: assert(false); break; case Statement::KindOfClassConstant: case Statement::KindOfGlobalStatement: case Statement::KindOfUnsetStatement: case Statement::KindOfExpStatement: case Statement::KindOfStatementList: case Statement::KindOfBlockStatement: case Statement::KindOfTryStatement: break; case Statement::KindOfIfStatement: break; case Statement::KindOfIfBranchStatement: { IfBranchStatementPtr ibr = static_pointer_cast<IfBranchStatement>(s); if (ibr->getCondition()) { if (ibr->getStmt()) { addEdge(ibr->getCondition(), AfterConstruct, ibr, AfterConstruct); addEdge(ibr->getStmt(), AfterConstruct, top(2), AfterConstruct); noFallThrough(ibr); } else { addEdge(ibr->getCondition(), AfterConstruct, top(2), AfterConstruct); } } break; } case Statement::KindOfForStatement: { ConstructPtr cond(s->getNthKid(ForStatement::CondExpr)); ConstructPtr body(s->getNthKid(ForStatement::BodyStmt)); ConstructPtr incr(s->getNthKid(ForStatement::IncExpr)); if (cond) addEdge(cond, AfterConstruct, s, AfterConstruct); ConstructPtr end = incr ? incr : body ? body : cond; ConstructPtr start = cond ? cond : body ? body : incr; if (end) addEdge(end, AfterConstruct, start, BeforeConstruct); noFallThrough(s); break; } case Statement::KindOfWhileStatement: { ConstructPtr cond(s->getNthKid(WhileStatement::CondExpr)); ConstructPtr body(s->getNthKid(WhileStatement::BodyStmt)); addEdge(cond, AfterConstruct, s, AfterConstruct); addEdge(body ? body : cond, AfterConstruct, cond, BeforeConstruct); noFallThrough(s); break; } case Statement::KindOfDoStatement: { ConstructPtr cond(s->getNthKid(DoStatement::CondExpr)); addEdge(cond, AfterConstruct, s, BeforeConstruct); break; } case Statement::KindOfForEachStatement: { ConstructPtr body(s->getNthKid(ForEachStatement::BodyStmt)); ConstructPtr name(s->getNthKid(ForEachStatement::NameExpr)); ConstructPtr value(s->getNthKid(ForEachStatement::ValueExpr)); ConstructPtr begin = name ? name : value; ConstructPtr end = body ? body : value; addEdge(end, AfterConstruct, begin, BeforeConstruct); addEdge(begin, BeforeConstruct, s, AfterConstruct); break; } case Statement::KindOfSwitchStatement: { SwitchStatementPtr sw(static_pointer_cast<SwitchStatement>(s)); ExpressionPtr exp = sw->getExp(); if (StatementListPtr cases = sw->getCases()) { addEdge(exp, AfterConstruct, s, AfterConstruct); for (int n = cases->getCount(), i = 0; i < n; ++i) { addEdge(exp, AfterConstruct, (*cases)[i], BeforeConstruct); } } break; } case Statement::KindOfCaseStatement: break; case Statement::KindOfReturnStatement: addEdge(s, AfterConstruct, root(), AfterConstruct); break; case Statement::KindOfBreakStatement: case Statement::KindOfContinueStatement: { int val = dynamic_pointer_cast<BreakStatement>(s)->getDepth(); size_t d = depth(); for (size_t i = 1; i < d; i++) { ConstructPtr c = top(i); if (LoopStatementPtr l = dynamic_pointer_cast<LoopStatement>(c)) { if (val <= 1) { if (stype == Statement::KindOfBreakStatement) { addEdge(s, AfterConstruct, l, AfterConstruct); } else { ConstructPtr kid; switch (l->getKindOf()) { case Statement::KindOfForEachStatement: kid = l->getNthKid(ForEachStatement::NameExpr); if (!kid) { kid = l->getNthKid(ForEachStatement::ValueExpr); } break; case Statement::KindOfForStatement: kid = l->getNthKid(ForStatement::IncExpr); if (!kid) kid = l->getNthKid(ForStatement::CondExpr); if (!kid) kid = l->getNthKid(ForStatement::BodyStmt); break; case Statement::KindOfWhileStatement: kid = l->getNthKid(WhileStatement::CondExpr); break; case Statement::KindOfDoStatement: kid = l->getNthKid(DoStatement::CondExpr); break; default: assert(0); } assert(kid); addEdge(s, AfterConstruct, kid, BeforeConstruct); } } if (val && !--val) break; } else if (SwitchStatementPtr sw = dynamic_pointer_cast<SwitchStatement>(c)) { if (val <= 1) { addEdge(s, AfterConstruct, sw, AfterConstruct); } if (val && !--val) break; } } break; } case Statement::KindOfThrowStatement: { size_t d = depth(); for (size_t i = 1; i < d; i++) { TryStatementPtr t = dynamic_pointer_cast<TryStatement>(top(i)); if (t) { StatementListPtr catches = t->getCatches(); for (int n = catches->getCount(), j = 0; j < n; ++j) { addEdge(s, AfterConstruct, (*catches)[j], BeforeConstruct); } break; } } break; } case Statement::KindOfCatchStatement: case Statement::KindOfEchoStatement: break; } } if (ControlFlowInfo *c = get(cp)) { if (c->m_targets[BeforeConstruct].size()) { if (!m_cur) newBlock(); m_ccbpMap[HoldingBlock][cp] = m_cur; endBlock(cp, BeforeConstruct); } else if (c->m_isTarget[BeforeConstruct]) { endBlock(cp, BeforeConstruct); } } if (!m_cur) newBlock(); m_ccbpMap[BeforeConstruct][cp] = m_cur; } else if (m_pass == 2) { ControlBlockPtr bb = m_ccbpMap[BeforeConstruct][cp]; assert(bb); if (bb != m_cur) { if (m_cur) { addCFEdge(m_cur, bb); } m_cur = bb; } if (ControlFlowInfo *c = get(cp)) { ConstructPtrLocMap &beforeTargets = c->m_targets[BeforeConstruct]; if (beforeTargets.size()) { ControlBlockPtr hb = m_ccbpMap[HoldingBlock][cp]; assert(hb); addCFEdge(hb, bb); ConstructPtrLocMap::iterator it = beforeTargets.begin(), end = beforeTargets.end(); while (it != end) { addCFEdge(hb, it->first, it->second); ++it; } } } } } return ret; }
int ControlFlowBuilder::before(ConstructRawPtr cp) { int ret = FunctionWalker::before(cp); if (ret == WalkContinue) { if (m_pass == 1) { if (StatementPtr s = dynamic_pointer_cast<Statement>(cp)) { if (FunctionWalker::SkipRecurse(s)) not_reached(); Statement::KindOf stype = s->getKindOf(); switch (stype) { case Statement::KindOfUseTraitStatement: case Statement::KindOfTraitPrecStatement: case Statement::KindOfTraitAliasStatement: not_reached(); case Statement::KindOfStaticStatement: addEdge(s, BeforeConstruct, s, AfterConstruct); break; case Statement::KindOfClassVariable: not_reached(); case Statement::KindOfClassConstant: case Statement::KindOfGlobalStatement: case Statement::KindOfUnsetStatement: case Statement::KindOfExpStatement: case Statement::KindOfStatementList: case Statement::KindOfBlockStatement: break; case Statement::KindOfTryStatement: { TryStatementPtr t = static_pointer_cast<TryStatement>(s); StatementListPtr catches = t->getCatches(); StatementPtr body = t->getBody(); FinallyStatementPtr finally = static_pointer_cast<FinallyStatement>(t->getFinally()); if (body) { for (int n = catches->getCount(), j = 0; j < n; ++j) { addEdge(body, BeforeConstruct, (*catches)[j], BeforeConstruct); addEdge(body, AfterConstruct, (*catches)[j], BeforeConstruct); } if (finally) { addEdge(body, BeforeConstruct, finally, BeforeConstruct); addEdge(body, AfterConstruct, finally, BeforeConstruct); } addEdge(body, AfterConstruct, t, AfterConstruct); noFallThrough(body); } break; } case Statement::KindOfThrowStatement: { size_t d = depth(); for (size_t i = 1; i < d; i++) { TryStatementPtr t = dynamic_pointer_cast<TryStatement>(top(i)); if (t) { StatementListPtr catches = t->getCatches(); for (int n = catches->getCount(), j = 0; j < n; ++j) { addEdge(s, AfterConstruct, (*catches)[j], BeforeConstruct); } break; } } break; } case Statement::KindOfFinallyStatement: break; case Statement::KindOfCatchStatement: break; case Statement::KindOfIfStatement: break; case Statement::KindOfIfBranchStatement: { IfBranchStatementPtr ibr = static_pointer_cast<IfBranchStatement>(s); if (ibr->getCondition()) { if (ibr->getStmt()) { addEdge(ibr->getCondition(), AfterConstruct, ibr, AfterConstruct); addEdge(ibr->getStmt(), AfterConstruct, top(2), AfterConstruct); noFallThrough(ibr); } else { addEdge(ibr->getCondition(), AfterConstruct, top(2), AfterConstruct); } } break; } case Statement::KindOfForStatement: { ForStatementPtr fs(static_pointer_cast<ForStatement>(s)); ConstructRawPtr body(fs->getBody()); ConstructRawPtr cond(fs->getCondExp()); ConstructRawPtr incr(fs->getIncExp()); if (cond) addEdge(cond, AfterConstruct, s, AfterConstruct); ConstructRawPtr end = incr ? incr : body ? body : cond; ConstructRawPtr start = cond ? cond : body ? body : incr; if (end) addEdge(end, AfterConstruct, start, BeforeConstruct); noFallThrough(s); break; } case Statement::KindOfWhileStatement: { WhileStatementPtr ws(static_pointer_cast<WhileStatement>(s)); ConstructRawPtr body(ws->getBody()); ConstructRawPtr cond(ws->getCondExp()); addEdge(cond, AfterConstruct, s, AfterConstruct); addEdge(body ? body : cond, AfterConstruct, cond, BeforeConstruct); noFallThrough(s); break; } case Statement::KindOfDoStatement: { DoStatementPtr ds(static_pointer_cast<DoStatement>(s)); addEdge(ds->getCondExp(), AfterConstruct, s, BeforeConstruct); break; } case Statement::KindOfForEachStatement: { ForEachStatementPtr fs(static_pointer_cast<ForEachStatement>(s)); ConstructRawPtr body(fs->getBody()); ConstructRawPtr name(fs->getNameExp()); ConstructRawPtr value(fs->getValueExp()); ConstructRawPtr begin = name ? name : value; ConstructRawPtr end = body ? body : value; addEdge(end, AfterConstruct, begin, BeforeConstruct); addEdge(value, AfterConstruct, s, AfterConstruct); break; } case Statement::KindOfSwitchStatement: { SwitchStatementPtr sw(static_pointer_cast<SwitchStatement>(s)); if (StatementListPtr cases = sw->getCases()) { ExpressionPtr exp; StatementPtr def; for (int n = cases->getCount(), i = 0; i < n; ++i) { CaseStatementPtr caseStmt = static_pointer_cast<CaseStatement>((*cases)[i]); if (!caseStmt->getCondition()) { def = caseStmt->getStatement(); } else { if (exp) { addEdge(exp, AfterConstruct, caseStmt, BeforeConstruct); } exp = caseStmt->getCondition(); } } if (exp) { if (def) { addEdge(exp, AfterConstruct, def, BeforeConstruct); } else { addEdge(exp, AfterConstruct, s, AfterConstruct); } } } break; } case Statement::KindOfCaseStatement: // already handled by switch break; case Statement::KindOfLabelStatement: { LabelStatementPtr l(static_pointer_cast<LabelStatement>(s)); m_labelInfoMap[l->label()].first = l; cfi(l).m_isTarget[BeforeConstruct] = true; break; } case Statement::KindOfGotoStatement: { GotoStatementPtr g(static_pointer_cast<GotoStatement>(s)); m_labelInfoMap[g->label()].second.push_back(g); noFallThrough(s); break; } case Statement::KindOfReturnStatement: { setEdge(s, AfterConstruct, root(), AfterConstruct); if (!m_isGenerator) noFallThrough(s); /* * Since almost anything in php /might/ throw, we * approximate, and add edges from the beginning and * end of a try block. But if there's a return, that * would kill the edge from the end of the block. * Explicitly add them here if the return is in a try */ size_t d = depth(); for (size_t i = 1; i < d; i++) { TryStatementPtr t = dynamic_pointer_cast<TryStatement>(top(i)); if (t) { StatementListPtr catches = t->getCatches(); for (int n = catches->getCount(), j = 0; j < n; ++j) { addEdge(s, AfterConstruct, (*catches)[j], BeforeConstruct); } break; } } break; } case Statement::KindOfBreakStatement: case Statement::KindOfContinueStatement: { noFallThrough(s); int val = dynamic_pointer_cast<BreakStatement>(s)->getDepth(); size_t d = depth(); for (size_t i = 1; i < d; i++) { ConstructRawPtr c = top(i); if (LoopStatementPtr l = dynamic_pointer_cast<LoopStatement>(c)) { if (val <= 1) { if (stype == Statement::KindOfBreakStatement) { addEdge(s, AfterConstruct, l, AfterConstruct); } else { ConstructRawPtr kid; switch (l->getKindOf()) { case Statement::KindOfForEachStatement: { ForEachStatementPtr fs(static_pointer_cast<ForEachStatement>(l)); kid = fs->getNameExp(); if (!kid) { kid = fs->getValueExp(); } break; } case Statement::KindOfForStatement: { ForStatementPtr fs(static_pointer_cast<ForStatement>(l)); kid = fs->getIncExp(); if (!kid) kid = fs->getCondExp(); if (!kid) kid = fs->getBody(); break; } case Statement::KindOfWhileStatement: { WhileStatementPtr ws(static_pointer_cast<WhileStatement>(l)); kid = ws->getCondExp(); break; } case Statement::KindOfDoStatement: { DoStatementPtr ds(static_pointer_cast<DoStatement>(l)); kid = ds->getCondExp(); break; } default: always_assert(0); } always_assert(kid); addEdge(s, AfterConstruct, kid, BeforeConstruct); } } if (val && !--val) break; } else if (SwitchStatementPtr sw = dynamic_pointer_cast<SwitchStatement>(c)) { if (val <= 1) { addEdge(s, AfterConstruct, sw, AfterConstruct); } if (val && !--val) break; } } break; } case Statement::KindOfEchoStatement: case Statement::KindOfTypedefStatement: break; default: not_reached(); } } else { ExpressionPtr e(dynamic_pointer_cast<Expression>(cp)); switch (e->getKindOf()) { case Expression::KindOfBinaryOpExpression: { BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(e)); if (b->isShortCircuitOperator()) { ConstructPtr trueBranch, falseBranch; ConstructLocation tLoc, fLoc; getTrueFalseBranches(0, trueBranch, tLoc, falseBranch, fLoc); assert(trueBranch); assert(falseBranch); if (b->isLogicalOrOperator()) { addEdge(b->getExp1(), AfterConstruct, trueBranch, tLoc); } else { addEdge(b->getExp1(), AfterConstruct, falseBranch, fLoc); } } break; } case Expression::KindOfQOpExpression: { QOpExpressionPtr q(static_pointer_cast<QOpExpression>(e)); if (ExpressionPtr e1 = q->getYes()) { addEdge(q->getCondition(), AfterConstruct, q->getNo(), BeforeConstruct); addEdge(e1, AfterConstruct, q->getNo(), AfterConstruct); noFallThrough(e1); } else { addEdge(q->getCondition(), AfterConstruct, q->getNo(), AfterConstruct); } break; } default: break; } } if (ControlFlowInfo *c = get(cp)) { if (c->m_targets[BeforeConstruct].size()) { if (!m_cur) newBlock(); m_ccbpMap[HoldingBlock][cp] = m_cur; endBlock(cp, BeforeConstruct); } else if (c->m_isTarget[BeforeConstruct]) { endBlock(cp, BeforeConstruct); } } if (!m_cur) newBlock(); m_ccbpMap[BeforeConstruct][cp] = m_cur; } else if (m_pass == 2) { ControlBlock *hb = m_ccbpMap[HoldingBlock][cp]; if (hb) { if (hb != m_cur) { if (m_cur) { addCFEdge(m_cur, hb); } m_cur = hb; } } ControlBlock *bb = m_ccbpMap[BeforeConstruct][cp]; always_assert(bb); if (bb != m_cur) { if (m_cur) { addCFEdge(m_cur, bb); } m_cur = bb; } if (ControlFlowInfo *c = get(cp)) { ConstructPtrLocMap &beforeTargets = c->m_targets[BeforeConstruct]; if (beforeTargets.size()) { always_assert(hb); addCFEdge(hb, bb); ConstructPtrLocMap::iterator it = beforeTargets.begin(), end = beforeTargets.end(); while (it != end) { addCFEdge(hb, it->first, it->second); ++it; } } } } } return ret; }