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;
}
Exemple #2
0
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());
      }
    }
  }
}