Exemple #1
0
bool AnalysisResult::checkClassPresent(ConstructPtr cs,
                                       const std::string &name) const {
  if (name == "self" || name == "parent") return true;
  std::string lowerName = toLower(name);
  if (ClassScopePtr currentCls = cs->getClassScope()) {
    if (lowerName == currentCls->getName() ||
        currentCls->derivesFrom(shared_from_this(), lowerName,
                                true, false)) {
      return true;
    }
  }
  if (FileScopePtr currentFile = cs->getFileScope()) {
    StatementList &stmts = *currentFile->getStmt();
    for (int i = stmts.getCount(); i--; ) {
      StatementPtr s = stmts[i];
      if (s && s->is(Statement::KindOfClassStatement)) {
        ClassScopePtr scope =
          static_pointer_cast<ClassStatement>(s)->getClassScope();
        if (lowerName == scope->getName()) {
          return true;
        }
        if (scope->derivesFrom(shared_from_this(), lowerName,
                               true, false)) {
          return true;
        }
      }
    }
  }
  return false;
}
Exemple #2
0
void ClassScope::informClosuresAboutScopeClone(
    ConstructPtr root,
    FunctionScopePtr outerScope,
    AnalysisResultPtr ar) {

  if (!root) {
    return;
  }

  for (int i = 0; i < root->getKidCount(); i++) {
    ConstructPtr cons = root->getNthKid(i);
    ClosureExpressionPtr closure =
      dynamic_pointer_cast<ClosureExpression>(cons);

    if (!closure) {
      informClosuresAboutScopeClone(cons, outerScope, ar);
      continue;
    }

    FunctionStatementPtr func = closure->getClosureFunction();
    HPHP::FunctionScopePtr funcScope = func->getFunctionScope();
    assert(funcScope->isClosure());
    funcScope->addClonedTraitOuterScope(outerScope);
    // Don't need to recurse
  }
}
Exemple #3
0
void AnalysisResult::analyzeProgram(ConstructPtr c) const {
  if (!c) return;
  for (auto i = 0, n = c->getKidCount(); i < n; ++i) {
    analyzeProgram(c->getNthKid(i));
  }
  c->analyzeProgram(AnalysisResultConstRawPtr{this});
}
Exemple #4
0
void Parser::addHphpNote(ConstructPtr c, const std::string &note) {
  if (note[0] == '@') {
    CodeError::ErrorType e;
    if (CodeError::lookupErrorType(note.substr(1), e)) {
      c->addSuppressError(e);
    } else {
      c->addHphpNote(note);
    }
  } else {
    c->addHphpNote(note);
  }
}
Exemple #5
0
int Construct::getChildrenEffects() const {
  int childrenEffects = NoEffect;
  for (int i = getKidCount(); i--; ) {
    ConstructPtr child = getNthKid(i);
    if (child) {
      childrenEffects |= child->getContainedEffects();
      if ((childrenEffects & UnknownEffect) == UnknownEffect) {
        break;
      }
    }
  }
  return childrenEffects;
}
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;
}
Exemple #7
0
int Construct::getChildrenEffects() const {
  int childrenEffects = NoEffect;
  for (int i = getKidCount(); i--; ) {
    ConstructPtr child = getNthKid(i);
    if (child) {
      if (FunctionWalker::SkipRecurse(child)) continue;
      childrenEffects |= child->getContainedEffects();
      if ((childrenEffects & UnknownEffect) == UnknownEffect) {
        break;
      }
    }
  }
  return childrenEffects;
}
Exemple #8
0
int CodeGenerator::createNewLocalId(ConstructPtr ar) {
  if (m_wrappedExpression[m_curStream]) {
    return m_localId[m_curStream]++;
  }
  FunctionScopePtr func = ar->getFunctionScope();
  if (func) {
    return func->nextInlineIndex();
  }
  FileScopePtr fs = ar->getFileScope();
  if (fs) {
    return createNewId(fs->getName());
  }
  return createNewId("");
}
Exemple #9
0
int CodeGenerator::createNewId(ConstructPtr cs) {
  FileScopePtr fs = cs->getFileScope();
  if (fs) {
    return createNewId(fs->getName());
  }
  return createNewId("");
}
string IncludeExpression::CheckInclude(ConstructPtr includeExp,
                                       ExpressionPtr fileExp,
                                       bool &documentRoot) {
  string container = includeExp->getLocation()->file;
  string var, lit;
  parse_string_arg(fileExp, var, lit);
  if (lit.empty()) return lit;

  if (var == "__DIR__") {
    var = "";
    // get_include_file_path will check relative to the current file's dir
    // as long as the first char isn't a /
    if (lit[0] == '/') {
      lit = lit.substr(1);
    }
  }

  string included = get_include_file_path(container, var, lit, documentRoot);
  if (!included.empty()) {
    if (included == container) {
      Compiler::Error(Compiler::BadPHPIncludeFile, includeExp);
    }
    included = Util::canonicalize(included);
    if (!var.empty()) documentRoot = true;
  }
  return included;
}
string DependencyGraph::add(KindOf kindOf, ConstructPtr childExp,
                            ExpressionPtr parentExp, CodeErrorPtr codeError,
                            bool documentRoot /* = false */) {
  string child = childExp->getLocation()->file;
  string parent;

  switch (kindOf) {
  case KindOfPHPInclude:
    if (!checkInclude(childExp, parentExp, codeError,
                      documentRoot, child, parent)) {
      return "";
    }
    break;
  default:
    if (!m_hookHandler ||
        !m_hookHandler(this, kindOf, childExp, parentExp, codeError,
                       documentRoot, child, parent,
                       beforeDependencyGraphAdd)) {
      return "";
    }
    break;
  }

  string program; // no program is associated
  add(kindOf, program, child, childExp, parent, ConstructPtr(), codeError);

  if (m_hookHandler) {
    m_hookHandler(this, kindOf, childExp, parentExp, codeError,
                  documentRoot, child, parent, afterDependencyGraphAdd);
  }
  return parent;
}
Exemple #12
0
ExpressionPtr Option::GetValue(VariableTablePtr variables,
                               const char *varName) {
  ConstructPtr decl = variables->getDeclaration(varName);
  if (!decl) {
    return ExpressionPtr();
  }

  AssignmentExpressionPtr assignment =
    dynamic_pointer_cast<AssignmentExpression>(decl);
  if (!assignment) {
    Logger::Error("Line %d: Ignored option %s", decl->getLocation()->line1,
                  varName);
    return ExpressionPtr();
  }

  return assignment->getValue();
}
Exemple #13
0
void Error(ErrorType error, ConstructPtr construct) {
  if (hhvm) return;
  ErrorInfoPtr errorInfo(new ErrorInfo());
  errorInfo->m_error = error;
  errorInfo->m_construct1 = construct;
  errorInfo->m_data = construct->getText();
  s_code_errors.record(errorInfo);
}
void ClassConstantExpression::outputCPPImpl(CodeGenerator &cg,
                                            AnalysisResultPtr ar) {
  const char *globals = "g";
  if (cg.getContext() == CodeGenerator::CppParameterDefaultValueDecl ||
      cg.getContext() == CodeGenerator::CppParameterDefaultValueImpl) {
    globals = cg.getGlobals();
  }
  if (m_valid) {
    ClassScopePtr foundCls;
    string trueClassName;
    for (ClassScopePtr cls = ar->findClass(m_className);
         cls; cls = cls->getParentScope(ar)) {
      if (cls->getConstants()->isPresent(m_varName)) {
        foundCls = cls;
        trueClassName = cls->getName();
        break;
      }
    }
    ASSERT(!trueClassName.empty());
    ConstructPtr decl = foundCls->getConstants()->getValue(m_varName);
    if (decl) {
      decl->outputCPP(cg, ar);
      if (cg.getContext() == CodeGenerator::CppImplementation ||
          cg.getContext() == CodeGenerator::CppParameterDefaultValueImpl) {
        cg.printf("(%s::%s)", m_className.c_str(), m_varName.c_str());
      } else {
        cg.printf("/* %s::%s */", m_className.c_str(), m_varName.c_str());
      }
    } else {
      if (foundCls->getConstants()->isDynamic(m_varName)) {
        cg.printf("%s%s::lazy_initializer(%s)->", Option::ClassPrefix,
                  trueClassName.c_str(), globals);
      }
      cg.printf("%s%s_%s", Option::ClassConstantPrefix, trueClassName.c_str(),
                m_varName.c_str());
    }
  } else if (m_redeclared) {
    cg.printf("%s->%s%s->os_constant(\"%s\")", globals,
              Option::ClassStaticsObjectPrefix,
              m_className.c_str(), m_varName.c_str());
  } else {
    cg.printf("throw_fatal(\"unknown class constant %s::%s\")",
              m_className.c_str(), m_varName.c_str());
  }
}
Exemple #15
0
void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
  if (!Option::RecordErrors) return;
  ErrorInfoPtr errorInfo(new ErrorInfo());
  errorInfo->m_error = error;
  errorInfo->m_construct1 = construct1;
  errorInfo->m_construct2 = construct2;
  errorInfo->m_data = construct1->getText();
  s_code_errors.record(errorInfo);
}
Exemple #16
0
void AliasManager::canonicalizeKid(ConstructPtr e, ExpressionPtr kid, int i) {
  if (kid) {
    kid = canonicalizeRecur(kid);
    if (kid) {
      e->setNthKid(i, kid);
      m_changed = true;
    }
  }
}
Exemple #17
0
  void walk_ast(ConstructPtr node) {
    if (!node) return;

    if (dynamic_pointer_cast<MethodStatement>(node)) {
      // Don't descend into nested non-closure functions, or functions
      // in the psuedo-main.
      return;
    }

    if (auto ce = dynamic_pointer_cast<ClosureExpression>(node)) {
      visit_closure(ce);
      return;
    }

    for (int i = 0; i < node->getKidCount(); ++i) {
      walk_ast(node->getNthKid(i));
    }
  }
void ConstantExpression::analyzeProgram(AnalysisResultPtr ar) {
  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    Symbol *sym = resolveNS(ar);
    if (!(m_context & LValue) && !m_dynamic) {
      if (sym && !sym->isSystem()) {
        if (sym->isDynamic()) {
          m_dynamic = true;
        } else {
          ConstructPtr decl = sym->getDeclaration();
          if (decl) {
            decl->getScope()->addUse(
              getScope(), BlockScope::UseKindConstRef);
            m_depsSet = true;
          }
        }
      }
    }
  }
}
Exemple #19
0
ClassScopePtr AnalysisResult::findExactClass(ConstructPtr cs,
                                             const std::string &name) const {
  ClassScopePtr cls = findClass(name);
  if (!cls || !cls->isRedeclaring()) return cls;
  if (ClassScopePtr currentCls = cs->getClassScope()) {
    if (cls->isNamed(currentCls->getScopeName())) {
      return currentCls;
    }
  }
  return ClassScopePtr();
}
Exemple #20
0
void Symbol::import(BlockScopeRawPtr scope, const Symbol &src_sym) {
  setName(src_sym.getName());
  setSystem();
  if (src_sym.declarationSet()) {
    ConstructPtr sc = src_sym.getDeclaration();
    if (sc) sc->resetScope(scope);
    setDeclaration(sc);
  }
  if (src_sym.valueSet()) {
    ConstructPtr sc = src_sym.getValue();
    if (sc) sc->resetScope(scope);
    setValue(sc);
  }
  if (src_sym.isDynamic()) {
    setDynamic();
  }
  if (src_sym.isConstant()) {
    setConstant();
  }
}
bool ClosureExpression::hasStaticLocalsImpl(ConstructPtr root) {
  if (!root) {
    return false;
  }
  if (root->getFunctionScope() != m_func->getFunctionScope()) {
    // new scope, new statics
    return false;
  }

  for (int i = 0; i < root->getKidCount(); i++) {
    ConstructPtr cons = root->getNthKid(i);
    if (StatementPtr s = dynamic_pointer_cast<Statement>(cons)) {
      if (s->is(Statement::KindOfStaticStatement)) {
        return true;
      }
    }
    if (hasStaticLocalsImpl(cons)) {
      return true;
    }
  }
  return false;
}
int Construct::getChildrenEffects() const {
  int childrenEffects = NoEffect;
  for (int i = getKidCount(); i--; ) {
    ConstructPtr child = getNthKid(i);
    if (child) {
      if (StatementPtr s = boost::dynamic_pointer_cast<Statement>(child)) {
        switch (s->getKindOf()) {
          case Statement::KindOfMethodStatement:
          case Statement::KindOfFunctionStatement:
          case Statement::KindOfClassStatement:
          case Statement::KindOfInterfaceStatement:
            continue;
          default:
            break;
        }
      }
      childrenEffects |= child->getContainedEffects();
      if ((childrenEffects & UnknownEffect) == UnknownEffect) {
        break;
      }
    }
  }
  return childrenEffects;
}
Exemple #23
0
  // Returns: whether or not $this is implicitly used in this part of the AST,
  // e.g. via a call using parent::.
  bool walk_ast(ConstructPtr node) {
    if (!node) return false;

    if (dynamic_pointer_cast<MethodStatement>(node)) {
      // Don't descend into nested non-closure functions, or functions
      // in the pseudo-main.
      return false;
    }

    if (auto ce = dynamic_pointer_cast<ClosureExpression>(node)) {
      return visit_closure(ce);
    }

    auto ret = false;
    if (auto fc = dynamic_pointer_cast<FunctionCall>(node)) {
      if (fc->isParent()) ret = true;
    }

    for (int i = 0; i < node->getKidCount(); ++i) {
      if (walk_ast(node->getNthKid(i))) ret = true;
    }

    return ret;
  }
bool DependencyGraph::checkInclude(ConstructPtr childExp,
                                   ExpressionPtr parentExp,
                                   CodeErrorPtr codeError,
                                   bool documentRoot,
                                   string &child,
                                   string &parent) {
  child = childExp->getLocation()->file;
  parent = parseInclude(child, parentExp, documentRoot);
  if ((parent.empty() || parent == child) &&
      Option::AllowedBadPHPIncludes.find(parentExp->getText()) ==
      Option::AllowedBadPHPIncludes.end()) {
    if (codeError) {
      codeError->record(CodeError::BadPHPIncludeFile, childExp);
    }
    return false;
  }
  if (parent.empty()) return false;
  return true;
}
void DependencyGraph::addParent(KindOf kindOf, const std::string &program,
                                const std::string &parentName,
                                ConstructPtr parent) {
  ASSERT(kindOf >= 0 && kindOf < KindOfCount);
  ASSERT(!parentName.empty());

  DependencyPtr &dep = m_parents[kindOf][parentName];
  if (!dep) {
    dep = DependencyPtr(new Dependency());
    dep->m_parent = parent;
    dep->m_programCount = 1;
    if (Option::DependencyMaxProgram && !program.empty()) {
      dep->m_programs.push_back(program);
    }
    m_parents[kindOf][parentName] = dep;
  } else if (parent && parent->hasHphpNote("MasterCopy")) {
    dep->m_parent = parent;
  }
}
string IncludeExpression::CheckInclude(ConstructPtr includeExp,
                                       ExpressionPtr fileExp,
                                       bool &documentRoot,
                                       bool relative) {
  string container = includeExp->getLocation()->file;
  string var, lit;
  parse_string_arg(fileExp, var, lit);
  if (lit.empty()) return lit;

  string included = get_include_file_path(container, var, lit,
                                          documentRoot, relative);
  if (!included.empty()) {
    if (included == container) {
      Compiler::Error(Compiler::BadPHPIncludeFile, includeExp);
    }
    included = Util::canonicalize(included);
    if (!var.empty()) documentRoot = true;
  }
  return included;
}
string IncludeExpression::CheckInclude(ConstructPtr includeExp,
                                       ExpressionPtr fileExp,
                                       bool documentRoot) {
  string container = includeExp->getLocation()->file;
  string var, lit;
  parse_string_arg(fileExp, var, lit);
  if (!lit.empty()) {
    if (!var.empty()) {
      var += " . ";
    }
    var += "'" + lit + "'";
  }

  string included = get_include_file_path(container, var, documentRoot);
  included = Util::canonicalize(included);
  if (included.empty() || container == included) {
    if (!included.empty() && included.find(' ') == string::npos) {
      Compiler::Error(Compiler::BadPHPIncludeFile, includeExp);
    }
    return "";
  }
  return included;
}
Exemple #28
0
void Construct::copyLocationTo(ConstructPtr other) {
  always_assert(other->getFileScope() == getFileScope());
  other->m_r = m_r;
}
Exemple #29
0
void Construct::dump(int spc, AnalysisResultPtr ar) {
  int nkid = getKidCount();
  std::string name;
  int type = 0;
  std::string scontext = "";
  std::string value = "";
  std::string type_info = "";
  unsigned id = 0;
  ExpressionPtr idPtr = ExpressionPtr();

  if (Statement *s = dynamic_cast<Statement*>(this)) {
    Statement::KindOf stype = s->getKindOf();
    switch (stype) {
    case Statement::KindOfFunctionStatement:
      name="FunctionStatement";
      break;
    case Statement::KindOfClassStatement:
      name="ClassStatement";
      break;
    case Statement::KindOfInterfaceStatement:
      name="InterfaceStatement";
      break;
    case Statement::KindOfClassVariable:
      name="ClassVariable";
      break;
    case Statement::KindOfClassConstant:
      name="ClassConstant";
      break;
    case Statement::KindOfMethodStatement:
      name="MethodStatement";
      break;
    case Statement::KindOfStatementList:
      name="StatementList";
      break;
    case Statement::KindOfBlockStatement:
      name="BlockStatement";
      break;
    case Statement::KindOfIfBranchStatement:
      name="IfBranchStatement";
      break;
    case Statement::KindOfIfStatement:
      name="IfStatement";
      break;
    case Statement::KindOfWhileStatement:
      name="WhileStatement";
      break;
    case Statement::KindOfDoStatement:
      name="DoStatement";
      break;
    case Statement::KindOfForStatement:
      name="ForStatement";
      break;
    case Statement::KindOfSwitchStatement:
      name="SwitchStatement";
      break;
    case Statement::KindOfCaseStatement:
      name="CaseStatement";
      break;
    case Statement::KindOfBreakStatement:
      name="BreakStatement";
      break;
    case Statement::KindOfContinueStatement:
      name="ContinueStatement";
      break;
    case Statement::KindOfReturnStatement:
      name="ReturnStatement";
      break;
    case Statement::KindOfGlobalStatement:
      name="GlobalStatement";
      break;
    case Statement::KindOfStaticStatement:
      name="StaticStatement";
      break;
    case Statement::KindOfEchoStatement:
      name="EchoStatement";
      break;
    case Statement::KindOfUnsetStatement:
      name="UnsetStatement";
      break;
    case Statement::KindOfExpStatement:
      name="ExpStatement";
      break;
    case Statement::KindOfForEachStatement:
      name="ForEachStatement";
      break;
    case Statement::KindOfCatchStatement:
      name="CatchStatement";
      break;
    case Statement::KindOfTryStatement:
      name="TryStatement";
      break;
    case Statement::KindOfThrowStatement:
      name="ThrowStatement";
      break;
    }
    type = (int)stype;
  } else if (Expression *e = dynamic_cast<Expression*>(this)) {
    id = e->getCanonID();
    idPtr = e->getCanonPtr();

    Expression::KindOf etype = e->getKindOf();
    switch (etype) {
    case Expression::KindOfSimpleFunctionCall:
      name="SimpleFunctionCall";
      value = static_cast<SimpleFunctionCall*>(e)->getName();
      break;
    case Expression::KindOfSimpleVariable:
      name="SimpleVariable";
      value = static_cast<SimpleVariable*>(e)->getName();
      break;
    case Expression::KindOfConstantExpression:
      name="ConstantExpression";
      value = e->getText();
      break;
    case Expression::KindOfScalarExpression:
      name="ScalarExpression";
      value = e->getText();
      break;

    case Expression::KindOfExpressionList:
      name="ExpressionList";
      break;
    case Expression::KindOfAssignmentExpression:
      name="AssignmentExpression";
      break;
    case Expression::KindOfDynamicVariable:
      name="DynamicVariable";
      break;
    case Expression::KindOfStaticMemberExpression:
      name="StaticMemberExpression";
      break;
    case Expression::KindOfArrayElementExpression:
      name="ArrayElementExpression";
      break;
    case Expression::KindOfDynamicFunctionCall:
      name="DynamicFunctionCall";
      break;
    case Expression::KindOfObjectPropertyExpression:
      name="ObjectPropertyExpression";
      break;
    case Expression::KindOfObjectMethodExpression:
      name="ObjectMethodExpression";
      break;
    case Expression::KindOfListAssignment:
      name="ListAssignment";
      break;
    case Expression::KindOfNewObjectExpression:
      name="NewObjectExpression";
      break;
    case Expression::KindOfUnaryOpExpression:
      name="UnaryOpExpression";
      break;
    case Expression::KindOfIncludeExpression:
      name="IncludeExpression";
      break;
    case Expression::KindOfBinaryOpExpression:
      name="BinaryOpExpression";
      break;
    case Expression::KindOfQOpExpression:
      name="QOpExpression";
      break;
    case Expression::KindOfArrayPairExpression:
      name="ArrayPairExpression";
      break;
    case Expression::KindOfClassConstantExpression:
      name="ClassConstantExpression";
      break;
    case Expression::KindOfParameterExpression:
      name="ParameterExpression";
      break;
    case Expression::KindOfModifierExpression:
      name="ModifierExpression";
      break;
    case Expression::KindOfEncapsListExpression:
      name="EncapsListExpression";
      break;
    }

    int c = e->getContext();
    if ((c & Expression::Declaration) == Expression::Declaration) {
      scontext += "|Declaration";
    } else if (c & Expression::LValue) {
      scontext += "|LValue";
    }
    if (c & Expression::NoLValueWrapper) {
      scontext += "|NoLValueWrapper";
    }
    if (c & Expression::RefValue) {
      scontext += "|RefValue";
    }
    if (c & Expression::RefParameter) {
      scontext += "|RefParameter";
    }
    if (c & Expression::DeepReference) {
      scontext += "|DeepReference";
    }
    if (c & Expression::NoRefWrapper) {
      scontext += "|NoRefWrapper";
    }
    if (c & Expression::ObjectContext) {
      scontext += "|ObjectContext";
    }
    if (c & Expression::InParameterExpression) {
      scontext += "|InParameterExpression";
    }
    if (c & Expression::ExistContext) {
      scontext += "|ExistContext";
    }
    if (c & Expression::UnsetContext) {
      scontext += "|UnsetContext";
    }
    if (c & Expression::AssignmentLHS) {
      scontext += "|AssignmentLHS";
    }
    if (c & Expression::DeepAssignmentLHS) {
      scontext += "|DeepAssignmentLHS";
    }
    if (c & Expression::InvokeArgument) {
      scontext += "|InvokeArgument";
    }
    if (c & Expression::OprLValue) {
      scontext += "|OprLValue";
    }
    if (c & Expression::DeepOprLValue) {
      scontext += "|DeepOprLValue";
    }

    if (scontext != "") {
      scontext = " (" + scontext.substr(1) + ")";
    }
    type = (int)etype;

    if (e->getActualType()) {
      type_info = e->getActualType()->toString();
      if (e->getExpectedType()) {
        type_info += ":" + e->getExpectedType()->toString();
      }
      if (e->getImplementedType()) {
        type_info += ";" + e->getImplementedType()->toString();
      }
      type_info = "{" + type_info + "} ";
    }
  } else {
    ASSERT(FALSE);
  }

  int s = spc;
  while (s > 0) {
    int n = s > 10 ? 10 : s;
    std::cout << ("          "+10-n);
    s -= n;
  }

  std::cout << "-> 0x" << hex << setfill('0') << setw(10) << (int64)this << dec;

  std::cout << " " << name << "(" << type << ") ";
  if (id) {
    std::cout << "id=" << id << " ";
  }
  if (idPtr) {
    std::cout << "idp=0x" <<
      hex << setfill('0') << setw(10) << (int64)idPtr.get() << " ";
  }

  if (value != "") {
    std::cout << "[" << value << "] ";
  }
  std::cout << type_info << nkid << scontext;
  if (m_loc) {
    std::cout << " " << m_loc->file << ":" <<
      m_loc->line1 << "@" << m_loc->char1;
  }
  std::cout << "\n";

  for (int i = 0; i < nkid; i++) {
    ConstructPtr kid = getNthKid(i);
    if (kid) {
      kid->dump(spc+2, ar);
    } else {
      int s = spc+2;
      while (s > 0) {
        int n = s > 10 ? 10 : s;
        std::cout << ("          "+10-n);
        s -= n;
      }
      std::cout << "-> (nokid)\n";
    }
  }
}
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp,
                                   ExpressionListPtr params, bool &valid) {
  if (!params) {
    if (m_minParam > 0) {
      if (exp->getScope()->isFirstPass()) {
        Compiler::Error(Compiler::TooFewArgument, exp, m_stmt);
      }
      valid = false;
      if (!Option::AllDynamic) setDynamic();
    }
    return 0;
  }

  int ret = 0;
  if (params->getCount() < m_minParam) {
    if (exp->getScope()->isFirstPass()) {
      Compiler::Error(Compiler::TooFewArgument, exp, m_stmt);
    }
    valid = false;
    if (!Option::AllDynamic) setDynamic();
  }
  if (params->getCount() > m_maxParam) {
    if (isVariableArgument()) {
      ret = params->getCount() - m_maxParam;
    } else {
      if (exp->getScope()->isFirstPass()) {
        Compiler::Error(Compiler::TooManyArgument, exp, m_stmt);
      }
      valid = false;
      if (!Option::AllDynamic) setDynamic();
    }
  }

  bool canSetParamType = isUserFunction() && !m_overriding && !m_perfectVirtual;
  for (int i = 0; i < params->getCount(); i++) {
    ExpressionPtr param = (*params)[i];
    if (i < m_maxParam && param->hasContext(Expression::RefParameter)) {
      /**
       * This should be very un-likely, since call time pass by ref is a
       * deprecated, not very widely used (at least in FB codebase) feature.
       */
      TRY_LOCK_THIS();
      Symbol *sym = getVariables()->addSymbol(m_paramNames[i]);
      sym->setLvalParam();
      sym->setCallTimeRef();
    }
    if (valid && param->hasContext(Expression::InvokeArgument)) {
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::NoRefWrapper);
    }
    bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument());
    if ((i < m_maxParam && isRefParam(i)) || isRefVararg) {
      param->setContext(Expression::LValue);
      param->setContext(Expression::RefValue);
      param->inferAndCheck(ar, Type::Variant, true);
    } else if (!(param->getContext() & Expression::RefParameter)) {
      param->clearContext(Expression::LValue);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::NoRefWrapper);
    }
    TypePtr expType;
    /**
     * Duplicate the logic of getParamType(i), w/o the mutation
     */
    TypePtr paramType(i < m_maxParam && !isZendParamMode() ?
                      m_paramTypes[i] : TypePtr());
    if (!paramType) paramType = Type::Some;
    if (valid && !canSetParamType && i < m_maxParam &&
        (!Option::HardTypeHints || !m_paramTypeSpecs[i])) {
      /**
       * What is this magic, you might ask?
       *
       * Here, we take advantage of implicit conversion from every type to
       * Variant. Essentially, we don't really care what type comes out of this
       * expression since it'll just get converted anyways. Doing it this way
       * allows us to generate less temporaries along the way.
       */
      TypePtr optParamType(paramType->is(Type::KindOfVariant) ?
                           Type::Some : paramType);
      expType = param->inferAndCheck(ar, optParamType, false);
    } else {
      expType = param->inferAndCheck(ar, Type::Some, false);
    }
    if (i < m_maxParam) {
      if (!Option::HardTypeHints || !m_paramTypeSpecs[i]) {
        if (canSetParamType) {
          if (!Type::SameType(paramType, expType) &&
              !paramType->is(Type::KindOfVariant)) {
            TRY_LOCK_THIS();
            paramType = setParamType(ar, i, expType);
          } else {
            // do nothing - how is this safe?  well, if we ever observe
            // paramType == expType, then this means at some point in the past,
            // somebody called setParamType() with expType.  thus, by calling
            // setParamType() again with expType, we contribute no "new"
            // information. this argument also still applies in the face of
            // concurrency
          }
        }
        // See note above. If we have an implemented type, however, we
        // should set the paramType to the implemented type to avoid an
        // un-necessary cast
        if (paramType->is(Type::KindOfVariant)) {
          TypePtr it(param->getImplementedType());
          paramType = it ? it : expType;
        }
        if (valid) {
          if (!Type::IsLegalCast(ar, expType, paramType) &&
              paramType->isNonConvertibleType()) {
            param->inferAndCheck(ar, paramType, true);
          }
          param->setExpectedType(paramType);
        }
      }
    }
    // we do a best-effort check for bad pass-by-reference and do not report
    // error for some vararg case (e.g., array_multisort can have either ref
    // or value for the same vararg).
    if (!isRefVararg || !isMixedVariableArgument()) {
      Expression::CheckPassByReference(ar, param);
    }
  }
  return ret;
}