void ClassScope::collectMethods(AnalysisResultPtr ar, StringToFunctionScopePtrMap &funcs, bool collectPrivate) { // add all functions this class has for (FunctionScopePtrVec::const_iterator iter = m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) { const FunctionScopePtr &fs = *iter; if (!collectPrivate && fs->isPrivate()) continue; FunctionScopePtr &func = funcs[fs->getScopeName()]; if (!func) { func = fs; } else { func->setVirtual(); fs->setVirtual(); fs->setHasOverride(); if (fs->isFinal()) { std::string s__MockClass = "__MockClass"; ClassScopePtr derivedClass = func->getContainingClass(); if (derivedClass->m_userAttributes.find(s__MockClass) == derivedClass->m_userAttributes.end()) { Compiler::Error(Compiler::InvalidOverride, fs->getStmt(), func->getStmt()); } } } } int n = m_bases.size(); for (int i = 0; i < n; i++) { const string &base = m_bases[i]; ClassScopePtr super = ar->findClass(base); if (super) { if (super->isRedeclaring()) { const ClassScopePtrVec &classes = ar->findRedeclaredClasses(base); StringToFunctionScopePtrMap pristine(funcs); for (auto& cls : classes) { StringToFunctionScopePtrMap cur(pristine); derivedMagicMethods(cls); cls->collectMethods(ar, cur, false); inheritedMagicMethods(cls); funcs.insert(cur.begin(), cur.end()); } m_derivesFromRedeclaring = Derivation::Redeclaring; setVolatile(); } else { derivedMagicMethods(super); super->collectMethods(ar, funcs, false); inheritedMagicMethods(super); if (super->derivesFromRedeclaring() == Derivation::Redeclaring) { m_derivesFromRedeclaring = Derivation::Redeclaring; setVolatile(); } else if (super->isVolatile()) { setVolatile(); } } } else { Compiler::Error(Compiler::UnknownBaseClass, m_stmt, base); if (base == m_parent) { ar->declareUnknownClass(m_parent); m_derivesFromRedeclaring = Derivation::Redeclaring; setVolatile(); } else { /* * TODO(#3685260): this should not be removing interfaces from * the base list. */ if (isInterface()) { m_derivesFromRedeclaring = Derivation::Redeclaring; } m_bases.erase(m_bases.begin() + i); n--; i--; } } } }
void AnalysisResult::analyzeProgram(bool system /* = false */) { AnalysisResultPtr ar = shared_from_this(); getVariables()->forceVariants(ar, VariableTable::AnyVars); getVariables()->setAttribute(VariableTable::ContainsLDynamicVariable); getVariables()->setAttribute(VariableTable::ContainsExtract); getVariables()->setAttribute(VariableTable::ForceGlobal); // Analyze Includes Logger::Verbose("Analyzing Includes"); sort(m_fileScopes.begin(), m_fileScopes.end(), by_filename); // fixed order unsigned int i = 0; for (i = 0; i < m_fileScopes.size(); i++) { collectFunctionsAndClasses(m_fileScopes[i]); } // Keep generated code identical without randomness canonicalizeSymbolOrder(); markRedeclaringClasses(); // Analyze some special cases for (set<string>::const_iterator it = Option::VolatileClasses.begin(); it != Option::VolatileClasses.end(); ++it) { ClassScopePtr cls = findClass(toLower(*it)); if (cls && cls->isUserClass()) { cls->setVolatile(); } } checkClassDerivations(); resolveNSFallbackFuncs(); // Analyze All Logger::Verbose("Analyzing All"); setPhase(AnalysisResult::AnalyzeAll); for (i = 0; i < m_fileScopes.size(); i++) { m_fileScopes[i]->analyzeProgram(ar); } /* Note that cls->collectMethods() can add entries to m_classDecs, which can invalidate iterators. So we have to create an array and then iterate over that. The new entries added to m_classDecs are always empty, so it doesnt matter that we dont include them in the iteration */ std::vector<ClassScopePtr> classes; classes.reserve(m_classDecs.size()); for (StringToClassScopePtrVecMap::const_iterator iter = m_classDecs.begin(); iter != m_classDecs.end(); ++iter) { for (ClassScopePtr cls: iter->second) { classes.push_back(cls); } } // Collect methods for (ClassScopePtr cls: classes) { if (cls->isRedeclaring()) { cls->setStaticDynamic(ar); } StringToFunctionScopePtrMap methods; cls->collectMethods(ar, methods, true /* include privates */); bool needAbstractMethodImpl = (!cls->isAbstract() && !cls->isInterface() && cls->derivesFromRedeclaring() == Derivation::Normal && !cls->getAttribute(ClassScope::UsesUnknownTrait)); for (StringToFunctionScopePtrMap::const_iterator iterMethod = methods.begin(); iterMethod != methods.end(); ++iterMethod) { FunctionScopePtr func = iterMethod->second; if (Option::WholeProgram && !func->hasImpl() && needAbstractMethodImpl) { FunctionScopePtr tmpFunc = cls->findFunction(ar, func->getName(), true, true); always_assert(!tmpFunc || !tmpFunc->hasImpl()); Compiler::Error(Compiler::MissingAbstractMethodImpl, func->getStmt(), cls->getStmt()); } m_methodToClassDecs[iterMethod->first].push_back(cls); } } ClassScopePtr cls; string cname; for (auto& sysclass_cls: m_systemClasses) { tie(cname, cls) = sysclass_cls; StringToFunctionScopePtrMap methods; cls->collectMethods(ar, methods, true /* include privates */); for (StringToFunctionScopePtrMap::const_iterator iterMethod = methods.begin(); iterMethod != methods.end(); ++iterMethod) { m_methodToClassDecs[iterMethod->first].push_back(cls); } } }