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); } } } }
void CodeGenerator::printStatementVector(StatementListPtr sl) { printf("V:9:\"HH\\Vector\":%d:{", sl->getCount()); if (sl->getCount() > 0) { sl->outputCodeModel(*this); } printf("}"); }
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); } } } }
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(); } } } } }
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); } } } }
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)); } } }
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; } }
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()); } } }
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; }
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; }
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()); } } }
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); } } }
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; }