void FunctionScope::setReturnType(AnalysisResultPtr ar, TypePtr type) { // no change can be made to virtual function's prototype if (m_overriding) return; if (m_returnType) { type = Type::Coerce(ar, m_returnType, type); if (type && !Type::SameType(m_returnType, type)) { ar->incNewlyInferred(); if (!ar->isFirstPass()) { Logger::Verbose("Corrected function return type %s -> %s", m_returnType->toString().c_str(), type->toString().c_str()); } } } if (!type->getName().empty()) { FileScopePtr fs = getFileScope(); if (fs) fs->addClassDependency(ar, type->getName()); } m_returnType = type; }
void MethodStatement::analyzeProgram(AnalysisResultPtr ar) { FunctionScopeRawPtr funcScope = getFunctionScope(); if (m_params) { m_params->analyzeProgram(ar); } if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { funcScope->setParamSpecs(ar); if (funcScope->isGenerator()) { MethodStatementRawPtr orig = getOrigGeneratorFunc(); VariableTablePtr variables = funcScope->getVariables(); orig->getFunctionScope()->addUse(funcScope, BlockScope::UseKindClosure); orig->getFunctionScope()->setContainsBareThis( funcScope->containsBareThis(), funcScope->containsRefThis()); orig->getFunctionScope()->setContainsThis(funcScope->containsThis()); if (ExpressionListPtr params = orig->getParams()) { for (int i = 0; i < params->getCount(); ++i) { auto param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); Symbol *gp = variables->addDeclaredSymbol(param->getName(), param); gp->setGeneratorParameter(); if (param->isRef()) { gp->setRefGeneratorParameter(); gp->setReferenced(); } } } if (ClosureExpressionRawPtr closure = orig->getContainingClosure()) { if (ExpressionListPtr cvars = closure->getClosureVariables()) { for (int i = 0; i < cvars->getCount(); ++i) { auto param = dynamic_pointer_cast<ParameterExpression>((*cvars)[i]); Symbol *gp = variables->addDeclaredSymbol( param->getName(), ConstructPtr()); gp->setGeneratorParameter(); if (param->isRef()) { gp->setRefGeneratorParameter(); gp->setReferenced(); } } } } } if (Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) { funcScope->setDynamic(); } // TODO: this may have to expand to a concept of "virtual" functions... if (m_method) { funcScope->disableInline(); if (m_name.length() > 2 && m_name.substr(0,2) == "__") { bool magic = true; int paramCount = 0; if (m_name == "__destruct") { funcScope->setOverriding(Type::Variant); } else if (m_name == "__call") { funcScope->setOverriding(Type::Variant, Type::String, Type::Array); paramCount = 2; } else if (m_name == "__set") { funcScope->setOverriding(Type::Variant, Type::String, Type::Variant); paramCount = 2; } else if (m_name == "__get") { funcScope->setOverriding(Type::Variant, Type::String); paramCount = 1; } else if (m_name == "__isset") { funcScope->setOverriding(Type::Boolean, Type::String); paramCount = 1; } else if (m_name == "__unset") { funcScope->setOverriding(Type::Variant, Type::String); paramCount = 1; } else if (m_name == "__sleep") { funcScope->setOverriding(Type::Variant); } else if (m_name == "__wakeup") { funcScope->setOverriding(Type::Variant); } else if (m_name == "__set_state") { funcScope->setOverriding(Type::Variant, Type::Variant); paramCount = 1; } else if (m_name == "__tostring") { funcScope->setOverriding(Type::String); } else if (m_name == "__clone") { funcScope->setOverriding(Type::Variant); } else { paramCount = -1; if (m_name != "__construct") { magic = false; } } if (paramCount >= 0 && paramCount != funcScope->getMaxParamCount()) { Compiler::Error(Compiler::InvalidMagicMethod, shared_from_this()); magic = false; } if (magic) funcScope->setMagicMethod(); } // ArrayAccess methods else if (m_name.length() > 6 && m_name.substr(0, 6) == "offset") { if (m_name == "offsetexists") { funcScope->setOverriding(Type::Boolean, Type::Variant); } else if (m_name == "offsetget") { funcScope->setOverriding(Type::Variant, Type::Variant); } else if (m_name == "offsetset") { funcScope->setOverriding(Type::Variant, Type::Variant, Type::Variant); } else if (m_name == "offsetunset") { funcScope->setOverriding(Type::Variant, Type::Variant); } } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { TypePtr ret = funcScope->getReturnType(); if (ret && ret->isSpecificObject()) { FileScopePtr fs = getFileScope(); if (fs) fs->addClassDependency(ar, ret->getName()); } if (!getFunctionScope()->usesLSB()) { if (StatementPtr orig = getOrigGeneratorFunc()) { orig->getFunctionScope()->clearUsesLSB(); } } } }
void MethodStatement::analyzeProgram(AnalysisResultPtr ar) { FunctionScopeRawPtr funcScope = getFunctionScope(); if (m_params) { m_params->analyzeProgram(ar); } if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { funcScope->setParamSpecs(ar); if (Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) { funcScope->setDynamic(); } // TODO: this may have to expand to a concept of "virtual" functions... if (m_method) { funcScope->disableInline(); if (m_name.length() > 2 && m_name.substr(0,2) == "__") { bool magic = true; int paramCount = 0; if (m_name == "__destruct") { funcScope->setOverriding(Type::Variant); } else if (m_name == "__call") { funcScope->setOverriding(Type::Variant, Type::String, Type::Array); paramCount = 2; } else if (m_name == "__set") { funcScope->setOverriding(Type::Variant, Type::String, Type::Variant); paramCount = 2; } else if (m_name == "__get") { funcScope->setOverriding(Type::Variant, Type::String); paramCount = 1; } else if (m_name == "__isset") { funcScope->setOverriding(Type::Boolean, Type::String); paramCount = 1; } else if (m_name == "__unset") { funcScope->setOverriding(Type::Variant, Type::String); paramCount = 1; } else if (m_name == "__sleep") { funcScope->setOverriding(Type::Variant); } else if (m_name == "__wakeup") { funcScope->setOverriding(Type::Variant); } else if (m_name == "__set_state") { funcScope->setOverriding(Type::Variant, Type::Variant); paramCount = 1; } else if (m_name == "__tostring") { funcScope->setOverriding(Type::String); } else if (m_name == "__clone") { funcScope->setOverriding(Type::Variant); } else { paramCount = -1; if (m_name != "__construct") { magic = false; } } if (paramCount >= 0 && paramCount != funcScope->getMaxParamCount()) { Compiler::Error(Compiler::InvalidMagicMethod, shared_from_this()); magic = false; } if (magic) funcScope->setMagicMethod(); } // ArrayAccess methods else if (m_name.length() > 6 && m_name.substr(0, 6) == "offset") { if (m_name == "offsetexists") { funcScope->setOverriding(Type::Boolean, Type::Variant); } else if (m_name == "offsetget") { funcScope->setOverriding(Type::Variant, Type::Variant); } else if (m_name == "offsetset") { funcScope->setOverriding(Type::Variant, Type::Variant, Type::Variant); } else if (m_name == "offsetunset") { funcScope->setOverriding(Type::Variant, Type::Variant); } } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { TypePtr ret = funcScope->getReturnType(); if (ret && ret->isSpecificObject()) { FileScopePtr fs = getFileScope(); if (fs) fs->addClassDependency(ar, ret->getName()); } } }