void SwitchStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  m_exp->analyzeProgram(ar);
  if (m_cases) m_cases->analyzeProgram(ar);

  if (ar->getPhase() == AnalysisResult::AnalyzeAll &&
      m_exp->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr exp = dynamic_pointer_cast<SimpleVariable>(m_exp);
    if (exp && exp->getSymbol() && exp->getSymbol()->isClassName()) {
      // Mark some classes as volitle since the name is used in switch
      for (int i = 0; i < m_cases->getCount(); i++) {
        CaseStatementPtr stmt =
          dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
        ASSERT(stmt);
        ExpressionPtr caseCond = stmt->getCondition();
        if (caseCond && caseCond->isScalar()) {
          ScalarExpressionPtr name =
            dynamic_pointer_cast<ScalarExpression>(caseCond);
          if (name && name->isLiteralString()) {
            string className = name->getLiteralString();
            ClassScopePtr cls = ar->findClass(Util::toLower(className));
            if (cls && cls->isUserClass()) {
              cls->setVolatile();
            }
          }
        }
      }
      // Also note this down as code error
      ConstructPtr self = shared_from_this();
      Compiler::Error(Compiler::ConditionalClassLoading, self);
    }
  }
}
示例#2
0
void NodeVisitor::visitCase(const CaseStatementPtr& node)
{
    for(auto condition : node->getConditions())
    {
        ACCEPT(condition.condition);
        ACCEPT(condition.guard);
    }
    ACCEPT(node->getCodeBlock());
}
示例#3
0
void SwitchStatement::inferTypes(AnalysisResultPtr ar) {
  // we optimize the most two common cases of switch statements
  bool allInteger = true;
  bool allString = true;
  if (m_cases && m_cases->getCount()) {
    for (int i = 0; i < m_cases->getCount(); i++) {
      CaseStatementPtr stmt =
        dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
      if (!stmt->getCondition()) {
        if (m_cases->getCount() == 1) allInteger = allString = false;
      } else {
        if (!stmt->isLiteralInteger()) allInteger = false;
        if (!stmt->isLiteralString()) allString = false;
      }
    }
  }
  if (allInteger && allString) {
    allInteger = allString = false;
  }

  TypePtr ret;
  if (allInteger) {
    ret = m_exp->inferAndCheck(ar, Type::Int64, false);
  } else if (allString) {
    // We're not able to do this, because switch($obj) may work on an object
    // that didn't implement __toString(), throwing an exception, which isn't
    // consistent with PHP.
    //ret = m_exp->inferAndCheck(ar, Type::String, false);
    ret = m_exp->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else {
    ret = m_exp->inferAndCheck(ar, NEW_TYPE(Some), false);
  }
  if (ret->is(Type::KindOfObject) && ret->isSpecificObject()) {
    m_exp->setExpectedType(NEW_TYPE(Object));
  }
  ConstructPtr self = shared_from_this();
  if (m_cases && m_cases->getCount()) {
    bool checking = false;
    vector<int> defaults;
    int defaultCount = 0;
    for (int i = 0; i < m_cases->getCount(); i++) {
      CaseStatementPtr stmt =
        dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
      stmt->inferAndCheck(ar, NEW_TYPE(Some), false);
      ExpressionPtr cond = stmt->getCondition();
      if (!cond) {
        checking = true;
        defaultCount++;
      } else if (checking && cond && ar->isFirstPass()) {
        defaults.push_back(i);
        ar->getCodeError()->record(self, CodeError::CaseAfterDefault, stmt);
      }
    }
    if (defaultCount > 1 && ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::MoreThanOneDefault, m_cases);
    }
  }
}
示例#4
0
void SwitchStatement::inferTypes(AnalysisResultPtr ar) {
  // we optimize the most two common cases of switch statements
  bool allInteger = true;
  bool allString = true;
  if (m_cases && m_cases->getCount()) {
    for (int i = 0; i < m_cases->getCount(); i++) {
      CaseStatementPtr stmt =
        dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
      if (!stmt->getCondition()) {
        if (m_cases->getCount() == 1) allInteger = allString = false;
      } else {
        if (!stmt->isLiteralInteger()) allInteger = false;
        if (!stmt->isLiteralString()) allString = false;
      }
    }
  }
  if (allInteger && allString) {
    allInteger = allString = false;
  }

  TypePtr ret = m_exp->inferAndCheck(ar, Type::Some, false);
  // these are the cases where toInt64(x) is OK for the switch statement
  if (allInteger && (ret->is(Type::KindOfInt32) || ret->is(Type::KindOfInt64))) {
    m_exp->setExpectedType(Type::Int64);
  }
  if (ret->is(Type::KindOfObject) && ret->isSpecificObject()) {
    m_exp->setExpectedType(Type::Object);
  }
  ConstructPtr self = shared_from_this();
  if (m_cases && m_cases->getCount()) {
    int defaultCount = 0;
    for (int i = 0; i < m_cases->getCount(); i++) {
      CaseStatementPtr stmt =
        dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
      stmt->inferAndCheck(ar, Type::Some, false);
      ExpressionPtr cond = stmt->getCondition();
      if (!cond) {
        defaultCount++;
      }
    }
    // TODO: this really belongs in analyzeProgram()
    if (defaultCount > 1 && getScope()->isFirstPass()) {
      Compiler::Error(Compiler::MoreThanOneDefault, m_cases);
    }
  }
}
示例#5
0
void Parser::parseSwitchStatements(const CaseStatementPtr& case_)
{
    Token token;
    Flags flags(this);
    flags -= SUPPRESS_TRAILING_CLOSURE;
    CodeBlockPtr codeBlock = case_->getCodeBlock();
    while(true)
    {
        expect_next(token);
        if(token.type == TokenType::Semicolon)
            continue;
        restore(token);
        Keyword::T k = token.getKeyword();
        if(token.type == TokenType::CloseBrace || (k == Keyword::Case || k == Keyword::Default))
        {
            break;
        }
        StatementPtr st = parseStatement();
        codeBlock->addStatement(st);
    }
        
}
void SwitchStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  int labelId = cg.createNewLocalId(shared_from_this());

  bool staticCases = true;
  if (!m_exp->getType()->isInteger()) {
    staticCases = false;
  } else if (m_cases) {
    bool seenDefault = false;
    set<int64> seenNums;
    for (int i = 0; i < m_cases->getCount(); i++) {
      CaseStatementPtr stmt =
        dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
      if (stmt->getCondition()) {
        if (!stmt->isLiteralInteger() || seenDefault) {
          staticCases = false;
          break;
        }

        // detecting duplicate case value
        int64 num = stmt->getLiteralInteger();
        if (seenNums.find(num) != seenNums.end()) {
          staticCases = false;
          break;
        }
        seenNums.insert(num);
      } else {
        seenDefault = true;
      }
    }
  }

  labelId |= CodeGenerator::InsideSwitch;
  if (staticCases) labelId |= CodeGenerator::StaticCases;
  cg.pushBreakScope(labelId, false);
  labelId &= ~CodeGenerator::BreakScopeBitMask;
  cg_indentBegin("{\n");

  string var;
  int varId = -1;

  if (m_exp->preOutputCPP(cg, ar, 0)) {
    varId = cg.createNewLocalId(shared_from_this());
    var = string(Option::SwitchPrefix) + lexical_cast<string>(varId);
    m_exp->getType()->outputCPPDecl(cg, ar, getScope());
    cg_printf(" %s;\n", var.c_str());

    m_exp->outputCPPBegin(cg, ar);
    cg_printf("%s = (", var.c_str());
    m_exp->outputCPP(cg, ar);
    cg_printf(");\n");
    m_exp->outputCPPEnd(cg, ar);
  }

  if (staticCases) {
    cg_printf("switch (");
    if (!var.empty()) {
      cg_printf("%s", var.c_str());
    } else {
      m_exp->outputCPP(cg, ar);
    }
    cg_printf(") {\n");
    if (m_cases) m_cases->outputCPP(cg, ar);
    cg_printf("}\n");
  } else {
    if (var.empty()) {
      varId = cg.createNewLocalId(shared_from_this());
      if (m_exp->hasContext(Expression::LValue) &&
          m_exp->is(Expression::KindOfSimpleVariable)) {
        var = getScope()->getVariables()->getVariableName(
          cg, ar, static_pointer_cast<SimpleVariable>(m_exp)->getName());
      } else {
        var = string(Option::SwitchPrefix) + lexical_cast<string>(varId);
        m_exp->getType()->outputCPPDecl(cg, ar, getScope());
        cg_printf(" %s = (", var.c_str());
        m_exp->outputCPP(cg, ar);
        cg_printf(");\n");
      }
    }

    if (m_cases && m_cases->getCount()) {
      CaseStatementPtr defaultCase;
      int defaultCaseNum = -1;
      for (int i = 0; i < m_cases->getCount(); i++) {
        CaseStatementPtr stmt =
          dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
        if (stmt->getCondition()) {
          stmt->outputCPPAsIf(cg, ar, varId, var.c_str(), i);
        } else {
          defaultCase = stmt;
          defaultCaseNum = i;
        }
      }
      if (defaultCaseNum != -1) {
        defaultCase->outputCPPAsIf(cg, ar, varId, var.c_str(), defaultCaseNum);
      } else {
        cg_printf("goto break%d;\n", labelId);
        cg.addLabelId("break", labelId);
      }
      cg_printf("\n");
      for (int i = 0; i < m_cases->getCount(); i++) {
        CaseStatementPtr stmt =
          dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
        stmt->outputCPPByNumber(cg, ar, varId,
                                !stmt->getCondition() && defaultCaseNum != i ?
                                -1 : i);
      }
    }
  }

  // Even though switch's break/continue will never goto these labels, we need
  // them for "break/continue n" inside switches.
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cg_indentEnd("}\n");
  cg.popBreakScope();
}
示例#7
0
/*
  GRAMMAR OF A SWITCH STATEMENT
 
 ‌ switch-statement -> switchexpression{switch-casesopt}
 ‌ switch-cases -> switch-case switch-cases opt
 ‌ switch-case -> case-labelstatements  |default-labelstatements
 ‌ switch-case -> case-label;  default-label;
 ‌ case-label -> casecase-item-list:
 ‌ case-item-list -> patternguard-clauseopt  patternguard-clauseopt,case-item-list
 ‌ default-label -> default:
 ‌ guard-clause -> whereguard-expression
 ‌ guard-expression -> expression
*/
StatementPtr Parser::parseSwitch()
{
    Token token;
    Flags flags(this, UNDER_SWITCH_CASE | SUPPRESS_TRAILING_CLOSURE);
    
    expect(Keyword::Switch, token);
    SwitchCasePtr ret = nodeFactory->createSwitch(token.state);
    {
        Flags f(flags);
        f += SUPPRESS_TRAILING_CLOSURE;
        ExpressionPtr controlExpr = parseExpression();
        ret->setControlExpression(controlExpr);
    }
    expect(L"{");
    // ‌ switch-cases -> switch-case switch-cases opt
    while(!predicate(L"}"))
    {
        //switch-case -> case-label statements  |default-label statements
        expect_next(token);
        tassert(token, token.type == TokenType::Identifier, Errors::E_EXPECT_CASE, token.token);
        // case-label -> casecase-item-list:
        if(token.identifier.keyword == Keyword::Case)
        {
            Flags fcase(flags);
            fcase += UNDER_CASE;
            
            //case-item-list -> pattern guard-clause opt | pattern guard-clause opt , case-item-list
            CaseStatementPtr caseCond = nodeFactory->createCase(token.state);
            CodeBlockPtr codeBlock = nodeFactory->createCodeBlock(token.state);
            caseCond->setCodeBlock(codeBlock);
            do
            {
                PatternPtr pattern = parsePattern();
                ExpressionPtr guard = NULL;
                if(match(L"where"))
                    guard = parseExpression();
                caseCond->addCondition(pattern, guard);
            }
            while(match(L","));
            expect(L":");
            ret->addCase(caseCond);
            parseSwitchStatements(caseCond);
            
        }
        else if(token.identifier.keyword == Keyword::Default)
        {
            expect(L":");
            CaseStatementPtr caseCond = nodeFactory->createCase(token.state);
            CodeBlockPtr codeBlock = nodeFactory->createCodeBlock(token.state);
            caseCond->setCodeBlock(codeBlock);
            parseSwitchStatements(caseCond);
            ret->setDefaultCase(caseCond);
        }
        else
        {
            tassert(token, false, Errors::E_EXPECT_CASE, token.token);
        }
        
    }
    expect(L"}");
    
    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;
}