bool TestDependGraph::VerifyDependency(DependencyGraph::KindOf kindOf, const char *input1, const char *input2 /* = NULL */, const char *parent /* = "f2" */, const char *child /* = "f1" */, const char *file /* = "" */, int line /* = 0 */) { ASSERT(input1); Option::IncludeRoots["$_SERVER['PHP_ROOT']"] = ""; AnalysisResultPtr ar(new AnalysisResult()); BuiltinSymbols::Load(ar); Parser::ParseString(input1, ar, "f1"); if (input2) Parser::ParseString(input2, ar, "f2"); ar->analyzeProgram(); ar->inferTypes(); DependencyGraphPtr dg = ar->getDependencyGraph(); const StringToConstructPtrMap &children = dg->getAllChildren(kindOf, parent); if ((*child && children.find(child) == children.end()) || (!*child && !children.empty())) { ostringstream graph; JSON::OutputStream(graph) << ar->getDependencyGraph(); printf("%s:%d: dependency missing\n%s\n", file, line, graph.str().c_str()); return false; } return true; }
void Package::addDependencyParents(const char *path, const char *postfix, DependencyGraph::KindOf kindOf) { vector<string> files; findFiles(files, path, postfix); DependencyGraphPtr dep = m_ar->getDependencyGraph(); int rootSize = m_root.size(); for (unsigned int i = 0; i < files.size(); i++) { const string &file = files[i]; ASSERT(file.substr(0, rootSize) == m_root); dep->addParent(kindOf, "", file.substr(rootSize), ConstructPtr()); } }
bool TestDependGraph::TestFunctionCall() { // functions VD4(FunctionCall, "<?php include $_SERVER['PHP_ROOT'].'f2';\n test();", "<?php function test() {}", "test", "test()"); VD4(FunctionCall, "<?php test(); function test() {}", "", "test", "test()"); VD4(FunctionCall, "<?php function test() {} test();", "", "test", "test()"); // methods VD4(FunctionCall, "<?php include $_SERVER['PHP_ROOT'].'f2';\n" "function test() { $a = new C(); $a->test();}", "<?php class C { public function test() {}}", "c::test", "$a->test()"); VD4(FunctionCall, "<?php function test() { $a = new C(); $a->test();} " "class C { public function test() {}}", "", "c::test", "$a->test()"); VD4(FunctionCall, "<?php class C { public function test() {}} " "function test() { $a = new C(); $a->test();}", "", "c::test", "$a->test()"); #ifdef HPHP_NOTE // making sure a "MasterCopy" marked function will always be used for // dependency's parent { Option::IncludeRoots["$_SERVER['PHP_ROOT']"] = ""; AnalysisResultPtr ar(new AnalysisResult()); BuiltinSymbols::Load(ar); Parser::ParseString("<?php function test() {}", ar, "f1"); Parser::ParseString("<?php /*|MasterCopy|*/ function test() {}", ar, "f2"); ar->analyzeProgram(); ar->inferTypes(); DependencyGraphPtr dg = ar->getDependencyGraph(); ConstructPtr parent = dg->getParent(DependencyGraph::KindOfFunctionCall, "test"); if (!parent || strcmp(parent->getLocation()->file, "f2") != 0) { printf("%s:%d: incorrect parent found at %s:%d\n", __FILE__, __LINE__, parent ? parent->getLocation()->file : "", parent ? parent->getLocation()->line0 : 0); return false; } } #endif return true; }
void ClassStatement::analyzeProgramImpl(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]); } ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) { classScope->setVolatile(); } checkVolatile(ar); if (m_stmt) { ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; DependencyGraphPtr dependencies = ar->getDependencyGraph(); 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 ))) { ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName().c_str()); } if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName().c_str()); m_parent = ""; m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }
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]); } ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) classScope->setVolatile(); FunctionScopePtr func = ar->getFunctionScope(); // redeclared classes are automatically volatile if (classScope->isVolatile()) { func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer); } if (m_stmt) { ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } DependencyGraphPtr dependencies = ar->getDependencyGraph(); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ClassScopePtr classScope = m_classScope.lock(); ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); m_parent = ""; m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }
void InterfaceStatement::analyzeProgramImpl(AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) classScope->setVolatile(); if (m_stmt) { classScope->setIncludeLevel(ar->getIncludeLevel()); ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } ar->recordClassSource(m_name, ar->getFileScope()->getName()); checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector<string> bases; if (m_base) m_base->getStrings(bases); DependencyGraphPtr dependencies = ar->getDependencyGraph(); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); } if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ClassScopePtr classScope = m_classScope.lock(); ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }