void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) { FunctionCall::analyzeProgram(ar); m_object->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { FunctionScopePtr func = m_funcScope; if (!func && m_object->isThis() && !m_origName.empty()) { ClassScopePtr cls = getClassScope(); if (cls) { m_classScope = cls; func = cls->findFunction(ar, m_origName, true, true); if (func && !cls->isInterface() && !(func->isVirtual() && (func->isAbstract() || (func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))))) { m_funcScope = func; func->addCaller(getScope()); } } } markRefParams(func, m_origName); } }
void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) { FunctionCall::analyzeProgram(ar); m_object->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { FunctionScopePtr func = m_funcScope; if (!func && m_object->isThis() && !m_name.empty()) { ClassScopePtr cls = getClassScope(); if (cls) { m_classScope = cls; func = cls->findFunction(ar, m_name, true, true); if (func && !cls->isInterface() && !(func->isVirtual() && (func->isAbstract() || (func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) && !func->isPerfectVirtual())) { m_funcScope = func; func->addCaller(getScope()); } } } markRefParams(func, m_name, canInvokeFewArgs()); } // This is OK because AnalyzeFinal is guaranteed to run for a CPP // target, regardless of opts (and we only need the following // for CPP targets) if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { // necessary because we set the expected type of m_object to // Type::Some during type inference. TypePtr at(m_object->getActualType()); TypePtr it(m_object->getImplementedType()); if (!m_object->isThis() && at && at->is(Type::KindOfObject)) { if (at->isSpecificObject() && it && Type::IsMappedToVariant(it)) { // fast-cast inference ClassScopePtr scope(ar->findClass(at->getName())); if (scope) { // add a dependency to m_object's class type // to allow the fast cast to succeed addUserClass(ar, at->getName()); } } m_object->setExpectedType(at); } } }
TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { assert(type); IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); resetTypes(); reset(); ConstructPtr self = shared_from_this(); TypePtr objectType = m_object->inferAndCheck(ar, Type::Some, false); m_valid = true; m_bindClass = true; if (m_name.empty()) { m_nameExp->inferAndCheck(ar, Type::Some, false); setInvokeParams(ar); // we have to use a variant to hold dynamic value return checkTypesImpl(ar, type, Type::Variant, coerce); } ClassScopePtr cls; if (objectType && !objectType->getName().empty()) { if (m_classScope && !strcasecmp(objectType->getName().c_str(), m_classScope->getName().c_str())) { cls = m_classScope; } else { cls = ar->findExactClass(shared_from_this(), objectType->getName()); } } if (!cls) { m_classScope.reset(); m_funcScope.reset(); m_valid = false; setInvokeParams(ar); return checkTypesImpl(ar, type, Type::Variant, coerce); } if (m_classScope != cls) { m_classScope = cls; m_funcScope.reset(); } FunctionScopePtr func = m_funcScope; if (!func) { func = cls->findFunction(ar, m_name, true, true); if (!func) { if (!cls->isTrait() && !cls->getAttribute(ClassScope::MayHaveUnknownMethodHandler) && !cls->getAttribute(ClassScope::HasUnknownMethodHandler) && !cls->getAttribute(ClassScope::InheritsUnknownMethodHandler)) { if (ar->classMemberExists(m_name, AnalysisResult::MethodName)) { if (!Option::AllDynamic) { setDynamicByIdentifier(ar, m_name); } } else { Compiler::Error(Compiler::UnknownObjectMethod, self); } } m_valid = false; setInvokeParams(ar); return checkTypesImpl(ar, type, Type::Variant, coerce); } m_funcScope = func; func->addCaller(getScope(), !type->is(Type::KindOfAny)); } bool valid = true; m_bindClass = func->isStatic(); // use $this inside a static function if (m_object->isThis()) { FunctionScopePtr localfunc = getFunctionScope(); if (localfunc->isStatic()) { if (getScope()->isFirstPass()) { Compiler::Error(Compiler::MissingObjectContext, self); } valid = false; } } // invoke() will return Variant if (cls->isInterface() || (func->isVirtual() && (!Option::WholeProgram || func->isAbstract() || (func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) && !func->isPerfectVirtual())) { valid = false; } if (!valid) { setInvokeParams(ar); checkTypesImpl(ar, type, Type::Variant, coerce); m_valid = false; // so we use invoke() syntax if (!Option::AllDynamic) { func->setDynamic(); } assert(m_actualType); return m_actualType; } assert(func); return checkParamsAndReturn(ar, type, coerce, func, false); }