void AssignmentExpression::onParse(AnalysisResultPtr ar, BlockScopePtr scope) { // This is that much we can do during parse phase. TypePtr type; if (m_value->is(Expression::KindOfScalarExpression)) { type = m_value->inferAndCheck(ar, 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 = 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); } 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 } }
TypePtr AssignmentExpression:: inferTypesImpl(AnalysisResultPtr ar, TypePtr type, bool coerce, ExpressionPtr variable, ExpressionPtr value /* = ExpressionPtr() */) { TypePtr ret = type; if (value) { if (coerce) { ret = value->inferAndCheck(ar, type, coerce); } else { ret = value->inferAndCheck(ar, NEW_TYPE(Some), coerce); } } BlockScopePtr scope = ar->getScope(); if (variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(variable); bool p; scope->getConstants()->check(exp->getName(), ret, true, ar, variable, p); } else if (variable->is(Expression::KindOfDynamicVariable)) { // simptodo: not too sure about this ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable); } else if (variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); if (var->getName() == "this" && ar->getClassScope()) { if (ar->isFirstPass()) { ar->getCodeError()->record(variable, CodeError::ReassignThis, variable); } } if (ar->getPhase() == AnalysisResult::LastInference && value) { if (!value->getExpectedType()) { value->setExpectedType(variable->getActualType()); } } } // if the value may involve object, consider the variable as "referenced" // so that objects are not destructed prematurely. bool referenced = true; if (value && value->isScalar()) referenced = false; if (ret && ret->isNoObjectInvolved()) referenced = false; if (referenced && variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); const std::string &name = var->getName(); VariableTablePtr variables = ar->getScope()->getVariables(); variables->addReferenced(name); } TypePtr vt = variable->inferAndCheck(ar, ret, true); if (!coerce && type->is(Type::KindOfAny)) { ret = vt; } return ret; }
void FileScope::addConstant(const string &name, TypePtr type, ExpressionPtr value, AnalysisResultPtr ar, ConstructPtr con) { BlockScopePtr f = ar->findConstantDeclarer(name); f->getConstants()->add(name, type, value, ar, con); }
ExpressionPtr SimpleFunctionCall::preOptimize(AnalysisResultPtr ar) { ar->preOptimize(m_nameExp); ar->preOptimize(m_params); if (ar->getPhase() != AnalysisResult::SecondPreOptimize) { return ExpressionPtr(); } // optimize away various "exists" functions, this may trigger // dead code elimination and improve type-inference. if (m_className.empty() && (m_type == DefinedFunction || m_type == FunctionExistsFunction || m_type == ClassExistsFunction || m_type == InterfaceExistsFunction) && m_params && m_params->getCount() == 1) { ExpressionPtr value = (*m_params)[0]; if (value->isScalar()) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value); if (name && name->isLiteralString()) { string symbol = name->getLiteralString(); switch (m_type) { case DefinedFunction: { ConstantTablePtr constants = ar->getConstants(); // system constant if (constants->isPresent(symbol)) { return CONSTANT("true"); } // user constant BlockScopePtr block = ar->findConstantDeclarer(symbol); // not found (i.e., undefined) if (!block) { if (symbol.find("::") == std::string::npos) { return CONSTANT("false"); } else { // e.g., defined("self::ZERO") return ExpressionPtr(); } } constants = block->getConstants(); // already set to be dynamic if (constants->isDynamic(symbol)) return ExpressionPtr(); ConstructPtr decl = constants->getValue(symbol); ExpressionPtr constValue = dynamic_pointer_cast<Expression>(decl); if (constValue->isScalar()) { return CONSTANT("true"); } else { return ExpressionPtr(); } break; } case FunctionExistsFunction: { const std::string &lname = Util::toLower(symbol); if (Option::DynamicInvokeFunctions.find(lname) == Option::DynamicInvokeFunctions.end()) { FunctionScopePtr func = ar->findFunction(lname); if (!func) { return CONSTANT("false"); } else if (!func->isVolatile()) { return CONSTANT("true"); } } break; } case InterfaceExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (!cls || !cls->isInterface()) { return CONSTANT("false"); } else if (!cls->isVolatile()) { return CONSTANT("true"); } break; } case ClassExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (!cls || cls->isInterface()) { return CONSTANT("false"); } else if (!cls->isVolatile()) { return CONSTANT("true"); } break; } default: ASSERT(false); } } } } return ExpressionPtr(); }
void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) { if (m_className.empty()) { addUserFunction(ar, m_name); } else if (m_className != "parent") { addUserClass(ar, m_className); } else { m_parentClass = true; } if (ar->getPhase() == AnalysisResult::AnalyzeInclude) { CHECK_HOOK(onSimpleFunctionCallAnalyzeInclude); ConstructPtr self = shared_from_this(); // We need to know the name of the constant so that we can associate it // with this file before we do type inference. if (m_className.empty() && m_type == DefineFunction) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); string varName; if (name) { varName = name->getIdentifier(); if (!varName.empty()) { ar->getFileScope()->declareConstant(ar, varName); } } // handling define("CONSTANT", ...); if (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]; ConstantTablePtr constants = ar->findConstantDeclarer(varName)->getConstants(); if (constants != ar->getConstants()) { constants->add(varName, NEW_TYPE(Some), value, ar, self); if (name->hasHphpNote("Dynamic")) { constants->setDynamic(ar, varName); } } } } } } if (m_type == UnserializeFunction) { ar->forceClassVariants(); } } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { // Look up the corresponding FunctionScope and ClassScope // for this function call { FunctionScopePtr func; ClassScopePtr cls; if (m_className.empty()) { func = ar->findFunction(m_name); } else { cls = ar->resolveClass(m_className); if (cls) { if (m_name == "__construct") { func = cls->findConstructor(ar, true); } else { func = cls->findFunction(ar, m_name, true, true); } } } if (func && !func->isRedeclaring()) { if (m_funcScope != func) { m_funcScope = func; Construct::recomputeEffects(); } } if (cls && !cls->isRedeclaring()) m_classScope = cls; } // check for dynamic constant and volatile function/class if (m_className.empty() && (m_type == DefinedFunction || m_type == FunctionExistsFunction || m_type == ClassExistsFunction || m_type == InterfaceExistsFunction) && m_params && m_params->getCount() >= 1) { ExpressionPtr value = (*m_params)[0]; if (value->isScalar()) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value); if (name && name->isLiteralString()) { string symbol = name->getLiteralString(); switch (m_type) { case DefinedFunction: { ConstantTablePtr constants = ar->getConstants(); if (!constants->isPresent(symbol)) { // user constant BlockScopePtr block = ar->findConstantDeclarer(symbol); if (block) { // found the constant constants = block->getConstants(); // set to be dynamic constants->setDynamic(ar, symbol); } } break; } case FunctionExistsFunction: { FunctionScopePtr func = ar->findFunction(Util::toLower(symbol)); if (func && func->isUserFunction()) { func->setVolatile(); } break; } case InterfaceExistsFunction: case ClassExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (cls && cls->isUserClass()) { cls->setVolatile(); } break; } default: ASSERT(false); } } } } } if (m_params) { if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (m_funcScope) { ExpressionList ¶ms = *m_params; int mpc = m_funcScope->getMaxParamCount(); for (int i = params.getCount(); i--; ) { ExpressionPtr p = params[i]; if (i < mpc ? m_funcScope->isRefParam(i) : m_funcScope->isReferenceVariableArgument()) { p->setContext(Expression::RefValue); } else if (!(p->getContext() & Expression::RefParameter)) { p->clearContext(Expression::RefValue); } } } else { FunctionScopePtr func = ar->findFunction(m_name); if (func && func->isRedeclaring()) { FunctionScope::RefParamInfoPtr info = FunctionScope::GetRefParamInfo(m_name); if (info) { for (int i = m_params->getCount(); i--; ) { if (info->isRefParam(i)) { m_params->markParam(i, canInvokeFewArgs()); } } } } else { m_params->markParams(false); } } } m_params->analyzeProgram(ar); } }