Exemplo n.º 1
0
void IncludeExpression::analyzeInclude(AnalysisResultPtr ar,
                                       const std::string &include) {
  ASSERT(ar->getPhase() == AnalysisResult::AnalyzeInclude);
  ConstructPtr self = shared_from_this();
  FileScopePtr file = ar->findFileScope(include, true);
  if (!file) {
    ar->getCodeError()->record(self, CodeError::PHPIncludeFileNotFound, self);
    return;
  }
  if (include.find("compiler/") != 0 ||
      include.find("/compiler/") == string::npos) {
    ar->getCodeError()->record(self, CodeError::PHPIncludeFileNotInLib,
                               self, ConstructPtr(),
                               include.c_str());
  }

  if (!isFileLevel()) { // Not unsupported but potentially bad
    ar->getCodeError()->record(self, CodeError::UseDynamicInclude, self);
  }

  ar->getDependencyGraph()->add
    (DependencyGraph::KindOfProgramMaxInclude,
     ar->getName(), file->getName(), StatementPtr());
  ar->getDependencyGraph()->addParent
    (DependencyGraph::KindOfProgramMinInclude,
     ar->getName(), file->getName(), StatementPtr());
  FunctionScopePtr func = ar->getFunctionScope();
  ar->getFileScope()->addIncludeDependency(ar, m_include,
                                           func && func->isInlined());
}
Exemplo n.º 2
0
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce,
                                           FunctionScopePtr func) {
  ConstructPtr self = shared_from_this();
  ar->getDependencyGraph()->add(DependencyGraph::KindOfFunctionCall,
                                ar->getName(), getText(),
                                self, func->getFullName(), func->getStmt());
  TypePtr frt = func->getReturnType();
  if (!frt) {
    m_voidReturn = true;
    setActualType(TypePtr());
    if (!type->is(Type::KindOfAny)) {
      if (!m_allowVoidReturn && ar->isSecondPass() && !func->isAbstract()) {
        ar->getCodeError()->record(self, CodeError::UseVoidReturn, self);
      }
      m_voidWrapper = true;
    }
  } else {
    m_voidReturn = false;
    m_voidWrapper = false;
    type = checkTypesImpl(ar, type, frt, coerce);
  }
  m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid);
  m_variableArgument = func->isVariableArgument();
  if (m_valid) {
    m_implementedType.reset();
  } else {
    m_implementedType = Type::Variant;
  }

  return type;
}
Exemplo n.º 3
0
void IncludeExpression::onParse(AnalysisResultPtr ar) {
  // See if we can get a string literal
  preOptimize(ar);
  m_include = ar->getDependencyGraph()->add
    (DependencyGraph::KindOfPHPInclude, shared_from_this(), m_exp,
     ar->getCodeError(), m_documentRoot);
}
Exemplo n.º 4
0
void SimpleFunctionCall::onParse(AnalysisResultPtr ar) {
    if (m_class) return;

    FileScopePtr fs = ar->getFileScope();
    ConstructPtr self = shared_from_this();
    if (m_className.empty()) {
        CodeErrorPtr codeError = ar->getCodeError();
        switch (m_type) {
        case CreateFunction:
            if (m_params->getCount() == 2 &&
                    (*m_params)[0]->isLiteralString() &&
                    (*m_params)[1]->isLiteralString()) {
                FunctionScopePtr func = ar->getFunctionScope();
                if (func) func->disableInline();
                string params = (*m_params)[0]->getLiteralString();
                string body = (*m_params)[1]->getLiteralString();
                m_lambda = CodeGenerator::GetNewLambda();
                string code = "function " + m_lambda + "(" + params + ") "
                              "{" + body + "}";
                ar->appendExtraCode(code);
            }
            break;
        case VariableArgumentFunction:
            ar->getFileScope()->setAttribute(FileScope::VariableArgument);
            break;
        case ExtractFunction:
            ar->getCodeError()->record(self, CodeError::UseExtract, self);
            ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable);
            ar->getFileScope()->setAttribute(FileScope::ContainsExtract);
            break;
        case CompactFunction:
            ar->getFileScope()->setAttribute(FileScope::ContainsDynamicVariable);
            ar->getFileScope()->setAttribute(FileScope::ContainsCompact);
            break;
        case ShellExecFunction:
            ar->getCodeError()->record(self, CodeError::UseShellExec, self);
            break;
        case GetDefinedVarsFunction:
            ar->getFileScope()->setAttribute(FileScope::ContainsGetDefinedVars);
            ar->getFileScope()->setAttribute(FileScope::ContainsCompact);
            break;
        default:
            CHECK_HOOK(onSimpleFunctionCallFuncType);
            break;
        }
    }

    string call = getText();
    string name = m_name;
    if (!m_className.empty()) {
        name = m_className + "::" + name;
    }
    ar->getDependencyGraph()->add(DependencyGraph::KindOfFunctionCall, call,
                                  shared_from_this(), name);
}
Exemplo n.º 5
0
void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar,
                                 StringToClassScopePtrMap &classes) {
  ASSERT(Loaded);
  classes.insert(s_classes.begin(), s_classes.end());

  // we are adding these builtin functions, so that user-defined functions
  // will not overwrite them with their own file and line number information
  for (StringToClassScopePtrMap::const_iterator iter =
         s_classes.begin(); iter != s_classes.end(); ++iter) {
    ar->getDependencyGraph()->addParent(DependencyGraph::KindOfClassDerivation,
                                        "", iter->first, StatementPtr());
  }
}
Exemplo n.º 6
0
void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
                                   StringToFunctionScopePtrVecMap &functions) {
  ASSERT(Loaded);
  for (StringToFunctionScopePtrMap::const_iterator it = s_functions.begin();
       it != s_functions.end(); ++it) {
    if (functions.find(it->first) == functions.end()) {
      functions[it->first].push_back(it->second);
      ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall,
                                          "", it->first, StatementPtr());
      FunctionScope::RecordRefParamInfo(it->first, it->second);
    }
  }
}
Exemplo n.º 7
0
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());
      }
    }
  }
}
Exemplo n.º 8
0
void GlobalStatement::inferTypes(AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();
  scope->getVariables()->setAttribute(VariableTable::InsideGlobalStatement);
  for (int i = 0; i < m_exp->getCount(); i++) {
    ExpressionPtr exp = (*m_exp)[i];
    if (exp->is(Expression::KindOfSimpleVariable)) {
      SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp);
      VariableTablePtr variables = scope->getVariables();
      const std::string &name = var->getName();
      /* If we have already seen this variable in the current scope and
         it is not a global variable, record this variable as "redeclared"
         which will force Variant type.
       */
      variables->checkRedeclared(name, KindOfGlobalStatement);

      /* If this is not a top-level global statement, the variable also
         needs to be Variant type. This should not be a common use case in
         php code.
       */
      if (!isTopLevel()) {
        variables->addNestedGlobal(name);
      }
      var->setContext(Expression::Declaration);
      var->inferAndCheck(ar, NEW_TYPE(Any), true);

      if (variables->needLocalCopy(name)) {
        variables->forceVariant(ar, name);
        variables->setAttribute(VariableTable::NeedGlobalPointer);
      }

      ConstructPtr decl =
        ar->getVariables()->getDeclaration(var->getName());
      if (decl) {
        ar->getDependencyGraph()->add(DependencyGraph::KindOfGlobalVariable,
                                      ar->getName(),
                                      var->getName(), var,
                                      var->getName(), decl);
      }
    } else {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(shared_from_this(), CodeError::UseDynamicGlobal, exp);
      }
      m_dynamicGlobal = true;
    }
  }
  FunctionScopePtr func = ar->getFunctionScope();
  scope->getVariables()->clearAttribute(VariableTable::InsideGlobalStatement);
}
Exemplo n.º 9
0
void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
                                   StringToFunctionScopePtrVecMap &functions) {
  ASSERT(Loaded);
  for (StringToFunctionScopePtrMap::const_iterator it = s_functions.begin();
       it != s_functions.end(); ++it) {
    functions[it->first].push_back(it->second);
  }

  // we are adding these builtin functions, so that user-defined functions
  // will not overwrite them with their own file and line number information
  for (StringToFunctionScopePtrMap::const_iterator iter =
         s_functions.begin(); iter != s_functions.end(); ++iter) {
    ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall,
                                        "", iter->first, StatementPtr());
  }
}
Exemplo n.º 10
0
ExpressionPtr IncludeExpression::preOptimize(AnalysisResultPtr ar) {
  if (ExpressionPtr rep = UnaryOpExpression::preOptimize(ar)) {
    return rep;
  }
  if (ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
    if (m_include.empty()) {
      m_include = ar->getDependencyGraph()->add
        (DependencyGraph::KindOfPHPInclude, shared_from_this(), m_exp,
         ar->getCodeError(), m_documentRoot);
      m_depsSet = false;
    }
    if (!m_depsSet && !m_include.empty()) {
      analyzeInclude(ar, m_include);
      m_depsSet = true;
    }
  }
  return ExpressionPtr();
}
Exemplo n.º 11
0
void FunctionStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  // registering myself as a parent in dependency graph, so that
  // (1) we can tell orphaned parents
  // (2) overwrite non-master copy of function declarations
  if (ar->isFirstPass()) {
    if (m_loc) {
      ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall,
                                          "", m_name, shared_from_this());
    } // else it's pseudoMain or artificial functions we added
  }
  FunctionScopePtr func = ar->getFunctionScope(); // containing function scope
  FunctionScopePtr fs = m_funcScope.lock();
  // redeclared functions are automatically volatile
  if (func && fs->isVolatile()) {
    func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer);
  }
  MethodStatement::analyzeProgramImpl(ar);
}
Exemplo n.º 12
0
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());
      }
    }
  }
}
Exemplo n.º 13
0
void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();

  // registering myself as a parent in dependency graph, so that
  // (1) we can tell orphaned parents
  // (2) overwrite non-master copy of function declarations
  if (ar->isFirstPass()) {
    ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall,
                                        "", getFullName(), shared_from_this());
    if (Option::AllDynamic || hasHphpNote("Dynamic") ||
        funcScope->isSepExtension() ||
        BuiltinSymbols::IsDeclaredDynamic(m_name) ||
        Option::IsDynamicFunction(m_method, m_name)) {
      funcScope->setDynamic();
    }
    if (hasHphpNote("Volatile")) funcScope->setVolatile();
  }

  funcScope->setIncludeLevel(ar->getIncludeLevel());
  ar->pushScope(funcScope);
  if (m_params) {
    m_params->analyzeProgram(ar);
    if (Option::GenRTTIProfileData &&
        ar->getPhase() == AnalysisResult::AnalyzeFinal) {
      addParamRTTI(ar);
    }
  }
  if (m_stmt) m_stmt->analyzeProgram(ar);

  if (ar->isFirstPass()) {
    if (!funcScope->isStatic() && ar->getClassScope() &&
        funcScope->getVariables()->
        getAttribute(VariableTable::ContainsDynamicVariable)) {
      // Add this to variable table if we'll need it in a lookup table
      // Use object because there's no point to specializing, just makes
      // code gen harder when dealing with redeclared classes.
      TypePtr tp(NEW_TYPE(Object));
      funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(),
                                     ModifierExpressionPtr());
    }
    FunctionScope::RecordRefParamInfo(m_name, funcScope);
  }
  ar->popScope();
}
Exemplo n.º 14
0
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());
      }
    }
  }
}
Exemplo n.º 15
0
void InterfaceStatement::onParse(AnalysisResultPtr ar) {
  vector<string> bases;
  if (m_base) m_base->getStrings(bases);

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  ClassScopePtr classScope(new ClassScope(ClassScope::KindOfInterface,
                                          m_name, "", bases, m_docComment, stmt,
                                          ar->getFileScope()));
  m_classScope = classScope;
  ar->getFileScope()->addClass(ar, classScope);
  ar->getDependencyGraph()->addParent(DependencyGraph::KindOfProgramUserClass,
                                      "", m_originalName, stmt);

  if (m_stmt) {
    ar->pushScope(classScope);
    for (int i = 0; i < m_stmt->getCount(); i++) {
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]);
      ph->onParse(ar);
    }
    ar->popScope();
  }
}
TypePtr ClassConstantExpression::inferTypes(AnalysisResultPtr ar,
                                            TypePtr type, bool coerce) {
  m_valid = false;
  ConstructPtr self = shared_from_this();
  ClassScopePtr cls = ar->resolveClass(m_className);
  if (!cls || cls->isRedeclaring()) {
    if (cls) {
      m_redeclared = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!cls && ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UnknownClass, self);
    }
    return type;
  }
  if (cls->getConstants()->isDynamic(m_varName)) {
    ar->getScope()->getVariables()->
      setAttribute(VariableTable::NeedGlobalPointer);
  }
  if (cls->getConstants()->isExplicitlyDeclared(m_varName)) {
    string name = m_className + "::" + m_varName;
    ConstructPtr decl = cls->getConstants()->getDeclaration(m_varName);
    if (decl) { // No decl means an extension class.
      ar->getDependencyGraph()->add(DependencyGraph::KindOfConstant,
                                    ar->getName(),
                                    name, shared_from_this(), name, decl);
    }
    m_valid = true;
  }
  bool present;
  TypePtr t = cls->checkConst(m_varName, type, coerce, ar,
                              shared_from_this(), present);
  if (present) {
    m_valid = true;
  }

  return t;
}
Exemplo n.º 17
0
void AssignmentExpression::onParse(AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();

  // This is that much we can do during parse phase.
  TypePtr type;
  if (m_value->is(Expression::KindOfScalarExpression)) {
    type = m_value->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else if (m_value->is(Expression::KindOfUnaryOpExpression)) {
    UnaryOpExpressionPtr uexp =
      dynamic_pointer_cast<UnaryOpExpression>(m_value);
    if (uexp->getOp() == T_ARRAY) {
      type = Type::Array;
    }
  }
  if (!type) type = NEW_TYPE(Some);

  if (m_variable->is(Expression::KindOfConstantExpression)) {
    // ...as in ClassConstant statement
    // We are handling this one here, not in ClassConstant, purely because
    // we need "value" to store in constant table.
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(m_variable);
    scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable);

    string name = ar->getClassScope()->getName() + "::" + exp->getName();
    ar->getDependencyGraph()->
      addParent(DependencyGraph::KindOfConstant, "", name, exp);
  } else if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable);
    scope->getVariables()->add(var->getName(), type, true, ar,
                               shared_from_this(), scope->getModifiers());
    var->clearContext(Declaration); // to avoid wrong CodeError
  } else {
    ASSERT(false); // parse phase shouldn't handle anything else
  }
}
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();


      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            ar->getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            ConstructPtr decl = vars->getDeclaration(m_globalName);
            if (decl) {
              ar->getDependencyGraph()->
                add(DependencyGraph::KindOfGlobalVariable,
                    ar->getName(),
                    m_globalName, self, m_globalName, decl);
            }
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            ar->getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }


      if (hasContext(LValue) || hasContext(RefValue)) {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseLDynamicVariable,
                                     self);
        }
        ar->getVariables()->forceVariants(ar);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      } else {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseRDynamicVariable,
                                     self);
        }
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, NEW_TYPE(Primitive), false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, NEW_TYPE(Sequence), false);
    m_offset->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::InvalidArrayElement,
                                   self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  if (hasContext(LValue) || hasContext(RefValue)) setEffect(CreateEffect);

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}
Exemplo n.º 19
0
TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
                                          bool coerce) {
  reset();

  ConstructPtr self = shared_from_this();

  // handling define("CONSTANT", ...);
  if (m_className.empty()) {
    if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        if (!varName.empty()) {
          ExpressionPtr value = (*m_params)[1];
          TypePtr varType = value->inferAndCheck(ar, NEW_TYPE(Some), false);
          ar->getDependencyGraph()->
            addParent(DependencyGraph::KindOfConstant,
                      ar->getName(), varName, self);
          ConstantTablePtr constants =
            ar->findConstantDeclarer(varName)->getConstants();
          if (constants != ar->getConstants()) {
            if (value && !value->isScalar()) {
              constants->setDynamic(ar, varName);
              varType = Type::Variant;
            }
            if (constants->isDynamic(varName)) {
              m_dynamicConstant = true;
              ar->getScope()->getVariables()->
                setAttribute(VariableTable::NeedGlobalPointer);
            } else {
              constants->setType(ar, varName, varType, true);
            }
            // in case the old 'value' has been optimized
            constants->setValue(ar, varName, value);
          }
          return checkTypesImpl(ar, type, Type::Boolean, coerce);
        }
      }
      if (varName.empty() && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::BadDefine, self);
      }
    } else if (m_type == ExtractFunction) {
      ar->getScope()->getVariables()->forceVariants(ar);
    }
  }

  FunctionScopePtr func;

  // avoid raising both MissingObjectContext and UnknownFunction
  bool errorFlagged = false;

  if (m_className.empty()) {
    func = ar->findFunction(m_name);
  } else {
    ClassScopePtr cls = ar->resolveClass(m_className);
    if (cls && cls->isVolatile()) {
      ar->getScope()->getVariables()
        ->setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!cls || cls->isRedeclaring()) {
      if (cls) {
        m_redeclaredClass = true;
      }
      if (!cls && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::UnknownClass, self);
      }
      if (m_params) {
        m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
      }
      return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_derivedFromRedeclaring = cls->derivesFromRedeclaring();
    m_validClass = true;

    if (m_name == "__construct") {
      // if the class is known, php will try to identify class-name ctor
      func = cls->findConstructor(ar, true);
    }
    else {
      func = cls->findFunction(ar, m_name, true, true);
    }

    if (func && !func->isStatic()) {
      ClassScopePtr clsThis = ar->getClassScope();
      FunctionScopePtr funcThis = ar->getFunctionScope();
      if (!clsThis ||
          (clsThis->getName() != m_className &&
           !clsThis->derivesFrom(ar, m_className)) ||
          funcThis->isStatic()) {
        // set the method static to avoid "unknown method" runtime exception
        if (Option::StaticMethodAutoFix && !func->containsThis()) {
          func->setStatic();
        }
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                     self);
          errorFlagged = true;
        }
        func.reset();
      }
    }
  }
  if (!func || func->isRedeclaring()) {
    if (func) {
      m_redeclared = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!func && !errorFlagged && ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UnknownFunction, self);
    }
    if (m_params) {
      if (func) {
        FunctionScope::RefParamInfoPtr info =
          FunctionScope::GetRefParamInfo(m_name);
        ASSERT(info);
        for (int i = m_params->getCount(); i--; ) {
          if (info->isRefParam(i)) {
            m_params->markParam(i, canInvokeFewArgs());
          }
        }
      }
      m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }
  m_builtinFunction = !func->isUserFunction();

  if (m_redeclared) {
    if (m_params) {
      m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    return checkTypesImpl(ar, type, type, coerce);
  }

  CHECK_HOOK(beforeSimpleFunctionCallCheck);

  m_valid = true;
  type = checkParamsAndReturn(ar, type, coerce, func);

  if (!m_valid && m_params) {
    m_params->markParams(false);
  }

  CHECK_HOOK(afterSimpleFunctionCallCheck);

  return type;
}