Beispiel #1
0
void ClassScope::applyTraitRules(AnalysisResultPtr ar) {
  assert(Option::WholeProgram);
  ClassStatementPtr classStmt = dynamic_pointer_cast<ClassStatement>(getStmt());
  assert(classStmt);
  StatementListPtr stmts = classStmt->getStmts();
  if (!stmts) return;
  for (int s = 0; s < stmts->getCount(); s++) {
    StatementPtr stmt = (*stmts)[s];

    UseTraitStatementPtr useStmt =
      dynamic_pointer_cast<UseTraitStatement>(stmt);
    if (!useStmt) continue;

    StatementListPtr rules = useStmt->getStmts();
    for (int r = 0; r < rules->getCount(); r++) {
      StatementPtr rule = (*rules)[r];
      TraitPrecStatementPtr precStmt =
        dynamic_pointer_cast<TraitPrecStatement>(rule);
      if (precStmt) {
        applyTraitPrecRule(precStmt);
      } else {
        TraitAliasStatementPtr aliasStmt =
          dynamic_pointer_cast<TraitAliasStatement>(rule);
        assert(aliasStmt);
        applyTraitAliasRule(ar, aliasStmt);
      }
    }
  }
}
Beispiel #2
0
void CodeGenerator::printStatementVector(StatementListPtr sl) {
  printf("V:9:\"HH\\Vector\":%d:{", sl->getCount());
  if (sl->getCount() > 0) {
    sl->outputCodeModel(*this);
  }
  printf("}");
}
Beispiel #3
0
void ClassScope::applyTraitRules(TMIData& tmid) {
  ClassStatementPtr classStmt =
    dynamic_pointer_cast<ClassStatement>(getStmt());
  assert(classStmt);

  StatementListPtr stmts = classStmt->getStmts();
  if (!stmts) return;

  for (int s = 0; s < stmts->getCount(); s++) {
    StatementPtr stmt = (*stmts)[s];

    UseTraitStatementPtr useStmt =
      dynamic_pointer_cast<UseTraitStatement>(stmt);
    if (!useStmt) continue;

    StatementListPtr rules = useStmt->getStmts();
    for (int r = 0; r < rules->getCount(); r++) {
      StatementPtr rule = (*rules)[r];
      TraitPrecStatementPtr precStmt =
        dynamic_pointer_cast<TraitPrecStatement>(rule);
      if (precStmt) {
        tmid.applyPrecRule(precStmt);
      } else {
        TraitAliasStatementPtr aliasStmt =
          dynamic_pointer_cast<TraitAliasStatement>(rule);
        assert(aliasStmt);
        tmid.applyAliasRule(aliasStmt, this);
      }
    }
  }
}
Beispiel #4
0
void FunctionScope::init(AnalysisResultConstPtr ar) {
    m_dynamicInvoke = false;

    if (isNamed("__autoload")) {
        setVolatile();
    }

    // FileScope's flags are from parser, but VariableTable has more flags
    // coming from type inference phase. So we are tranferring these flags
    // just for better modularization between FileScope and VariableTable.
    if (m_attribute & FileScope::ContainsDynamicVariable) {
        m_variables->setAttribute(VariableTable::ContainsDynamicVariable);
    }
    if (m_attribute & FileScope::ContainsLDynamicVariable) {
        m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
    }
    if (m_attribute & FileScope::ContainsExtract) {
        m_variables->setAttribute(VariableTable::ContainsExtract);
    }
    if (m_attribute & FileScope::ContainsAssert) {
        m_variables->setAttribute(VariableTable::ContainsAssert);
    }
    if (m_attribute & FileScope::ContainsCompact) {
        m_variables->setAttribute(VariableTable::ContainsCompact);
    }
    if (m_attribute & FileScope::ContainsUnset) {
        m_variables->setAttribute(VariableTable::ContainsUnset);
    }
    if (m_attribute & FileScope::ContainsGetDefinedVars) {
        m_variables->setAttribute(VariableTable::ContainsGetDefinedVars);
    }

    if (m_stmt && Option::AllVolatile && !m_pseudoMain && !m_method) {
        m_volatile = true;
    }

    if (!m_method && Option::DynamicInvokeFunctions.find(m_scopeName) !=
            Option::DynamicInvokeFunctions.end()) {
        setDynamicInvoke();
    }
    if (m_modifiers) {
        m_virtual = m_modifiers->isAbstract();
    }

    if (m_stmt) {
        MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
        StatementListPtr stmts = stmt->getStmts();
        if (stmts) {
            for (int i = 0; i < stmts->getCount(); i++) {
                StatementPtr stmt = (*stmts)[i];
                stmt->setFileLevel();
                if (stmt->is(Statement::KindOfExpStatement)) {
                    ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
                    ExpressionPtr exp = expStmt->getExpression();
                    exp->setTopLevel();
                }
            }
        }
    }
}
Beispiel #5
0
MethodStatementPtr
ClassScope::findTraitMethod(AnalysisResultPtr ar,
                            ClassScopePtr trait,
                            const string &methodName,
                            std::set<ClassScopePtr> &visitedTraits) {
  if (visitedTraits.find(trait) != visitedTraits.end()) {
    return MethodStatementPtr();
  }
  visitedTraits.insert(trait);

  ClassStatementPtr tStmt =
    dynamic_pointer_cast<ClassStatement>(trait->getStmt());
  StatementListPtr tStmts = tStmt->getStmts();

  // Look in the current trait
  for (int s = 0; s < tStmts->getCount(); s++) {
    MethodStatementPtr meth =
      dynamic_pointer_cast<MethodStatement>((*tStmts)[s]);
    if (meth) {    // Handle methods
      if (meth->getName() == methodName) {
        return meth;
      }
    }
  }

  // Look into children traits
  for (int s = 0; s < tStmts->getCount(); s++) {
    UseTraitStatementPtr useTraitStmt =
      dynamic_pointer_cast<UseTraitStatement>((*tStmts)[s]);
    if (useTraitStmt) {
      vector<string> usedTraits;
      useTraitStmt->getUsedTraitNames(usedTraits);
      for (unsigned i = 0; i < usedTraits.size(); i++) {
        MethodStatementPtr foundMethod =
          findTraitMethod(ar, ar->findClass(usedTraits[i]), methodName,
                          visitedTraits);
        if (foundMethod) return foundMethod;
      }
    }
  }
  return MethodStatementPtr(); // not found
}
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) {
  vector<string> bases;
  if (!m_parent.empty()) bases.push_back(m_parent);
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    string className = bases[i];
    addUserClass(ar, bases[i]);
  }

  checkVolatile(ar);

  if (m_stmt) {
    m_stmt->analyzeProgram(ar);
  }

  ClassScopePtr clsScope = getClassScope();

  // Check that every trait stmt is either a method, class_var, or trait_use
  if (clsScope->isTrait()) {
    StatementListPtr stmts = getStmts();
    if (stmts) {
      for (int s = 0; s < stmts->getCount(); s++) {
        StatementPtr stmt = (*stmts)[s];
        if(!dynamic_pointer_cast<UseTraitStatement>(stmt) &&
           !dynamic_pointer_cast<MethodStatement>(stmt) &&
           !dynamic_pointer_cast<ClassVariable>(stmt)) {
          Compiler::Error(Compiler::InvalidTraitStatement, stmt);
        }
      }
    }
  }

  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;

  clsScope->importUsedTraits(ar);

  ar->recordClassSource(m_name, m_loc, getFileScope()->getName());
  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) ||
          (cls->isInterface() && (!m_parent.empty() && i == 0 )) ||
          (cls->isTrait())) {
        Compiler::Error(Compiler::InvalidDerivation, shared_from_this(),
                        cls->getOriginalName());
      }
      if (cls->isUserClass()) {
        cls->addUse(getScope(), BlockScope::UseKindParentRef);
      }
    }
  }
}
Beispiel #7
0
void FileScope::setFileLevel(StatementListPtr stmtList) {
  for (int i = 0; i < stmtList->getCount(); i++) {
    StatementPtr stmt = (*stmtList)[i];
    stmt->setFileLevel();
    if (stmt->is(Statement::KindOfExpStatement)) {
      ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
      ExpressionPtr exp = expStmt->getExpression();
      exp->setFileLevel();
    }
    if (stmt->is(Statement::KindOfStatementList)) {
      setFileLevel(dynamic_pointer_cast<StatementList>(stmt));
    }
  }
}
Beispiel #8
0
void ClassScope::findTraitMethodsToImport(AnalysisResultPtr ar,
                                          ClassScopePtr trait) {
  assert(Option::WholeProgram);
  ClassStatementPtr tStmt =
    dynamic_pointer_cast<ClassStatement>(trait->getStmt());
  StatementListPtr tStmts = tStmt->getStmts();
  if (!tStmts) return;

  for (int s = 0; s < tStmts->getCount(); s++) {
    MethodStatementPtr meth =
      dynamic_pointer_cast<MethodStatement>((*tStmts)[s]);
    if (meth) {
      TraitMethod traitMethod(trait, meth, ModifierExpressionPtr(),
                              MethodStatementPtr());
      addImportTraitMethod(traitMethod, meth->getName());
    }
  }
}
void ClassStatement::GetCtorAndInitInfo(
    StatementPtr s, bool &needsCppCtor, bool &needsInit) {
  if (!s) return;
  switch (s->getKindOf()) {
  case Statement::KindOfStatementList:
    {
      StatementListPtr stmts = static_pointer_cast<StatementList>(s);
      for (int i = 0; i < stmts->getCount(); i++) {
        GetCtorAndInitInfo((*stmts)[i], needsCppCtor, needsInit);
      }
    }
    break;
  case Statement::KindOfClassVariable:
    {
      ClassVariablePtr cv = static_pointer_cast<ClassVariable>(s);
      cv->getCtorAndInitInfo(needsCppCtor, needsInit);
    }
    break;
  default: break;
  }
}
Beispiel #10
0
void ClassScope::importTraitProperties(AnalysisResultPtr ar) {

  for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
    ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
    if (!tCls) continue;
    ClassStatementPtr tStmt =
      dynamic_pointer_cast<ClassStatement>(tCls->getStmt());
    StatementListPtr tStmts = tStmt->getStmts();
    if (!tStmts) continue;
    for (int s = 0; s < tStmts->getCount(); s++) {
      ClassVariablePtr prop =
        dynamic_pointer_cast<ClassVariable>((*tStmts)[s]);
      if (prop) {
        ClassVariablePtr cloneProp = dynamic_pointer_cast<ClassVariable>(
          dynamic_pointer_cast<ClassStatement>(m_stmt)->addClone(prop));
        cloneProp->resetScope(shared_from_this());
        cloneProp->addTraitPropsToScope(ar,
                      dynamic_pointer_cast<ClassScope>(shared_from_this()));
      }
    }
  }
}
void ClassStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) {
  ClassScope::KindOf kindOf = ClassScope::KindOfObjectClass;
  switch (m_type) {
  case T_CLASS:     kindOf = ClassScope::KindOfObjectClass;   break;
  case T_ABSTRACT:  kindOf = ClassScope::KindOfAbstractClass; break;
  case T_FINAL:     kindOf = ClassScope::KindOfFinalClass;    break;
  case T_TRAIT:     kindOf = ClassScope::KindOfTrait;         break;
  default:
    assert(false);
  }

  vector<string> bases;
  if (!m_originalParent.empty()) {
    bases.push_back(m_originalParent);
  }
  if (m_base) m_base->getOriginalStrings(bases);

  for (auto &b : bases) {
    ar->parseOnDemandByClass(Util::toLower(b));
  }

  vector<UserAttributePtr> attrs;
  if (m_attrList) {
    for (int i = 0; i < m_attrList->getCount(); ++i) {
      UserAttributePtr a =
        dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]);
      attrs.push_back(a);
    }
  }

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  ClassScopePtr classScope(new ClassScope(kindOf, m_originalName,
                                          m_originalParent,
                                          bases, m_docComment,
                                          stmt, attrs));
  setBlockScope(classScope);
  if (!fs->addClass(ar, classScope)) {
    m_ignored = true;
    return;
  }

  if (Option::PersistenceHook) {
    classScope->setPersistent(Option::PersistenceHook(classScope, fs));
  }

  if (m_stmt) {
    MethodStatementPtr constructor;

    // flatten continuation StatementList into MethodStatements
    for (int i = 0; i < m_stmt->getCount(); i++) {
      StatementListPtr stmts =
        dynamic_pointer_cast<StatementList>((*m_stmt)[i]);
      if (stmts) {
        m_stmt->removeElement(i);
        for (int j = 0; j < stmts->getCount(); j++) {
          m_stmt->insertElement((*stmts)[j], i + j);
        }
      }
    }

    for (int i = 0; i < m_stmt->getCount(); i++) {
      MethodStatementPtr meth =
        dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
      if (meth && meth->getName() == "__construct") {
        constructor = meth;
        break;
      }
    }
    for (int i = 0; i < m_stmt->getCount(); i++) {
      if (!constructor) {
        MethodStatementPtr meth =
          dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
        if (meth && meth->getName() == classScope->getName()
            && !classScope->isTrait()) {
          // class-name constructor
          constructor = meth;
          classScope->setAttribute(ClassScope::ClassNameConstructor);
        }
      }
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]);
      ph->onParseRecur(ar, classScope);
    }
    if (constructor && constructor->getModifiers()->isStatic()) {
      constructor->parseTimeFatal(Compiler::InvalidAttribute,
                                  "Constructor %s::%s() cannot be static",
                                  classScope->getOriginalName().c_str(),
                                  constructor->getOriginalName().c_str());
    }
  }
}
Beispiel #12
0
void FunctionScope::init(AnalysisResultConstPtr ar) {
  m_dynamicInvoke = false;
  bool canInline = true;
  if (m_pseudoMain) {
    canInline = false;
    m_variables->forceVariants(ar, VariableTable::AnyVars);
    setReturnType(ar, Type::Variant);
  }

  if (m_refReturn) {
    m_returnType = Type::Variant;
  }

  if (!strcasecmp(m_name.c_str(), "__autoload")) {
    setVolatile();
  }

  // FileScope's flags are from parser, but VariableTable has more flags
  // coming from type inference phase. So we are tranferring these flags
  // just for better modularization between FileScope and VariableTable.
  if (m_attribute & FileScope::ContainsDynamicVariable) {
    m_variables->setAttribute(VariableTable::ContainsDynamicVariable);
  }
  if (m_attribute & FileScope::ContainsLDynamicVariable) {
    m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
  }
  if (m_attribute & FileScope::ContainsExtract) {
    m_variables->setAttribute(VariableTable::ContainsExtract);
  }
  if (m_attribute & FileScope::ContainsAssert) {
    m_variables->setAttribute(VariableTable::ContainsAssert);
  }
  if (m_attribute & FileScope::ContainsCompact) {
    m_variables->setAttribute(VariableTable::ContainsCompact);
  }
  if (m_attribute & FileScope::ContainsUnset) {
    m_variables->setAttribute(VariableTable::ContainsUnset);
  }
  if (m_attribute & FileScope::ContainsGetDefinedVars) {
    m_variables->setAttribute(VariableTable::ContainsGetDefinedVars);
  }

  if (m_stmt && Option::AllVolatile && !m_pseudoMain && !m_method) {
    m_volatile = true;
  }

  m_dynamic = Option::IsDynamicFunction(m_method, m_name) ||
    Option::EnableEval == Option::FullEval || Option::AllDynamic;
  if (!m_method && Option::DynamicInvokeFunctions.find(m_name) !=
      Option::DynamicInvokeFunctions.end()) {
    setDynamicInvoke();
  }
  if (m_modifiers) {
    m_virtual = m_modifiers->isAbstract();
  }

  if (m_stmt) {
    MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
    StatementListPtr stmts = stmt->getStmts();
    if (stmts) {
      if (stmts->getRecursiveCount() > Option::InlineFunctionThreshold)
        canInline = false;
      for (int i = 0; i < stmts->getCount(); i++) {
        StatementPtr stmt = (*stmts)[i];
        stmt->setFileLevel();
        if (stmt->is(Statement::KindOfExpStatement)) {
          ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
          ExpressionPtr exp = expStmt->getExpression();
          exp->setTopLevel();
        }
      }
    }
  } else {
    canInline = false;
  }
  m_inlineable = canInline;
}
Beispiel #13
0
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;
}
Beispiel #14
0
void ClassStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) {
  ClassScope::KindOf kindOf = ClassScope::KindOf::ObjectClass;
  switch (m_type) {
    case T_CLASS:     kindOf = ClassScope::KindOf::ObjectClass;   break;
    case T_ABSTRACT:  kindOf = ClassScope::KindOf::AbstractClass; break;
    case T_STATIC: // Slight hack: see comments in hphp.y
      kindOf = ClassScope::KindOf::UtilClass;     break;
    case T_FINAL:     kindOf = ClassScope::KindOf::FinalClass;    break;
    case T_TRAIT:     kindOf = ClassScope::KindOf::Trait;         break;
    case T_ENUM:      kindOf = ClassScope::KindOf::Enum;          break;
    default:
      assert(false);
  }

  std::vector<std::string> bases;
  if (!m_originalParent.empty()) {
    bases.push_back(m_originalParent);
  }
  if (m_base) m_base->getStrings(bases);

  for (auto &b : bases) {
    ar->parseOnDemandByClass(b);
  }

  std::vector<UserAttributePtr> attrs;
  if (m_attrList) {
    for (int i = 0; i < m_attrList->getCount(); ++i) {
      UserAttributePtr a =
        dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]);
      attrs.push_back(a);
    }
  }

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  auto classScope = std::make_shared<ClassScope>(
    fs, kindOf, m_originalName,
    m_originalParent,
    bases, m_docComment,
    stmt, attrs);

  setBlockScope(classScope);
  if (!fs->addClass(ar, classScope)) {
    m_ignored = true;
    return;
  }

  classScope->setPersistent(false);

  if (m_stmt) {
    MethodStatementPtr constructor = nullptr;
    MethodStatementPtr destructor = nullptr;
    MethodStatementPtr clone = nullptr;

    // flatten continuation StatementList into MethodStatements
    for (int i = 0; i < m_stmt->getCount(); i++) {
      StatementListPtr stmts =
        dynamic_pointer_cast<StatementList>((*m_stmt)[i]);
      if (stmts) {
        m_stmt->removeElement(i);
        for (int j = 0; j < stmts->getCount(); j++) {
          m_stmt->insertElement((*stmts)[j], i + j);
        }
      }
    }

    for (int i = 0; i < m_stmt->getCount(); i++) {
      MethodStatementPtr meth =
        dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
      if (meth) {
        if (meth->isNamed("__construct")) {
          constructor = meth;
          continue;
        }
        if (meth->isNamed("__destruct")) {
          destructor = meth;
          continue;
        }
        if (meth->isNamed("__clone")) {
          clone = meth;
          continue;
        }
      }
      if (constructor && destructor && clone) {
        break;
      }
    }

    for (int i = 0; i < m_stmt->getCount(); i++) {
      if (!constructor) {
        MethodStatementPtr meth =
          dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
        if (meth &&
            meth->isNamed(classScope->getOriginalName()) &&
            !classScope->isTrait()) {
          // class-name constructor
          constructor = meth;
          classScope->setAttribute(ClassScope::ClassNameConstructor);
        }
      }
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]);
      ph->onParseRecur(ar, fs, classScope);
    }
    if (constructor && constructor->getModifiers()->isStatic()) {
      constructor->parseTimeFatal(fs,
                                  Compiler::InvalidAttribute,
                                  "Constructor %s::%s() cannot be static",
                                  classScope->getOriginalName().c_str(),
                                  constructor->getOriginalName().c_str());
    }
    if (destructor && destructor->getModifiers()->isStatic()) {
      destructor->parseTimeFatal(fs,
                                 Compiler::InvalidAttribute,
                                 "Destructor %s::%s() cannot be static",
                                 classScope->getOriginalName().c_str(),
                                 destructor->getOriginalName().c_str());
    }
    if (clone && clone->getModifiers()->isStatic()) {
      clone->parseTimeFatal(fs,
                            Compiler::InvalidAttribute,
                            "Clone method %s::%s() cannot be static",
                            classScope->getOriginalName().c_str(),
                            clone->getOriginalName().c_str());
    }
  }
}
Beispiel #15
0
void ClassStatement::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) {
  ClassScope::KindOf kindOf = ClassScope::KindOfObjectClass;
  switch (m_type) {
  case T_CLASS:     kindOf = ClassScope::KindOfObjectClass;   break;
  case T_ABSTRACT:  kindOf = ClassScope::KindOfAbstractClass; break;
  case T_FINAL:     kindOf = ClassScope::KindOfFinalClass;    break;
  default:
    ASSERT(false);
  }

  vector<string> bases;
  if (!m_parent.empty()) {
    bases.push_back(m_parent);
  }
  if (m_base) m_base->getStrings(bases);
  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  ClassScopePtr classScope(new ClassScope(kindOf, m_originalName, m_parent,
                                          bases, m_docComment,
                                          stmt));
  setBlockScope(classScope);
  if (!fs->addClass(ar, classScope)) {
    m_ignored = true;
    return;
  }

  if (m_stmt) {
    bool seenConstruct = false;

    // flatten continuation StatementList into MethodStatements
    for (int i = 0; i < m_stmt->getCount(); i++) {
      StatementListPtr stmts =
        dynamic_pointer_cast<StatementList>((*m_stmt)[i]);
      if (stmts) {
        m_stmt->removeElement(i);
        for (int j = 0; j < stmts->getCount(); j++) {
          m_stmt->insertElement((*stmts)[j], i + j);
        }
      }
    }

    for (int i = 0; i < m_stmt->getCount(); i++) {
      MethodStatementPtr meth =
        dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
      if (meth && meth->getName() == "__construct") {
        seenConstruct = true;
        break;
      }
    }
    for (int i = 0; i < m_stmt->getCount(); i++) {
      if (!seenConstruct) {
        MethodStatementPtr meth =
          dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
        if (meth && classScope && meth->getName() == classScope->getName()
         && !meth->getModifiers()->isStatic()) {
          // class-name constructor
          classScope->setAttribute(ClassScope::ClassNameConstructor);
        }
      }
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]);
      ph->onParseRecur(ar, classScope);
    }
  }
}
Beispiel #16
0
FunctionScope::FunctionScope(AnalysisResultPtr ar, bool method,
                             const std::string &name, StatementPtr stmt,
                             bool reference, int minParam, int maxParam,
                             ModifierExpressionPtr modifiers,
                             int attribute, const std::string &docComment,
                             FileScopePtr file,
                             bool inPseudoMain /* = false */)
    : BlockScope(name, docComment, stmt, BlockScope::FunctionScope),
    m_method(method), m_file(file), m_minParam(0), m_maxParam(0),
    m_attribute(attribute), m_refReturn(reference), m_modifiers(modifiers),
    m_virtual(false), m_overriding(false), m_redeclaring(-1),
    m_volatile(false), m_ignored(false), m_pseudoMain(inPseudoMain),
    m_magicMethod(false), m_system(false), m_inlineable(false), m_sep(false),
    m_containsThis(false), m_staticMethodAutoFixed(false),
    m_callTempCountMax(0), m_callTempCountCurrent(0) {
  bool canInline = true;
  if (inPseudoMain) {
    canInline = false;
    m_variables->forceVariants(ar);
    setReturnType(ar, Type::Variant);
  }
  setParamCounts(ar, minParam, maxParam);

  if (m_refReturn) {
    m_returnType = Type::Variant;
  }

  // FileScope's flags are from parser, but VariableTable has more flags
  // coming from type inference phase. So we are tranferring these two
  // flags just for better modularization between FileScope and VariableTable.
  if (m_attribute & FileScope::ContainsDynamicVariable) {
    m_variables->setAttribute(VariableTable::ContainsDynamicVariable);
  }
  if (m_attribute & FileScope::ContainsLDynamicVariable) {
    m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
  }
  if (m_attribute & FileScope::ContainsExtract) {
    m_variables->setAttribute(VariableTable::ContainsExtract);
  }
  if (m_attribute & FileScope::ContainsCompact) {
    m_variables->setAttribute(VariableTable::ContainsCompact);
  }
  if (m_attribute & FileScope::ContainsUnset) {
    m_variables->setAttribute(VariableTable::ContainsUnset);
  }
  if (m_attribute & FileScope::ContainsGetDefinedVars) {
    m_variables->setAttribute(VariableTable::ContainsGetDefinedVars);
  }

  if (m_stmt && Option::AllVolatile) {
    m_volatile = true;
  }

  m_dynamic = Option::IsDynamicFunction(method, m_name) ||
    Option::EnableEval == Option::FullEval;
  if (modifiers) {
    m_virtual = modifiers->isAbstract();
  }

  if (m_stmt) {
    MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
    StatementListPtr stmts = stmt->getStmts();
    if (stmts) {
      if (stmts->getRecursiveCount() > Option::InlineFunctionThreshold)
        canInline = false;
      for (int i = 0; i < stmts->getCount(); i++) {
        StatementPtr stmt = (*stmts)[i];
        stmt->setFileLevel();
        if (stmt->is(Statement::KindOfExpStatement)) {
          ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
          ExpressionPtr exp = expStmt->getExpression();
          exp->setTopLevel();
        }
      }
    }
  } else {
    canInline = false;
  }
  m_inlineable = canInline;
}
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;
}