Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -1238,7 +1238,7 @@ class CallDescription { friend CallEvent; - mutable IdentifierInfo *II = nullptr; + mutable const IdentifierInfo *II = nullptr; mutable bool IsLookupDone = false; // The list of the qualified names used to identify the specified CallEvent, // e.g. "{a, b}" represent the qualified names, like "a::b". @@ -1283,6 +1283,10 @@ /// Get the name of the function that this object matches. StringRef getFunctionName() const { return QualifiedName.back(); } + + /// Get the qualifiers in reversed order. + auto begin_qualifiers() const { return std::next(QualifiedName.rbegin()); } + auto end_qualifiers() const { return QualifiedName.rend(); } }; /// An immutable map from CallDescriptions to arbitrary data. Provides a unified Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -307,10 +307,7 @@ if (getKind() == CE_ObjCMessage) return false; - const IdentifierInfo *II = getCalleeIdentifier(); - if (!II) - return false; - const FunctionDecl *FD = dyn_cast_or_null(getDecl()); + const auto *FD = dyn_cast_or_null(getDecl()); if (!FD) return false; @@ -326,38 +323,68 @@ CD.getFunctionName()); } - if (II != CD.II) - return false; + const auto MatchNameOnly = [&CD](const NamedDecl *ND) -> bool { + DeclarationName Name = ND->getDeclName(); + if (const auto *II = Name.getAsIdentifierInfo()) + return II == CD.II; // Fast case. - // If CallDescription provides prefix names, use them to improve matching - // accuracy. - if (CD.QualifiedName.size() > 1 && FD) { - const DeclContext *Ctx = FD->getDeclContext(); - // See if we'll be able to match them all. - size_t NumUnmatched = CD.QualifiedName.size() - 1; - for (; Ctx && isa(Ctx); Ctx = Ctx->getParent()) { - if (NumUnmatched == 0) - break; + // If it's not a simple identifier, e.g. C++ overload, constructor, operator + // call, simply report mismatch. + return false; + }; - if (const auto *ND = dyn_cast(Ctx)) { - if (ND->getName() == CD.QualifiedName[NumUnmatched - 1]) - --NumUnmatched; - continue; - } + const auto ExactMatchArgAndParamCounts = + [this](const CallDescription &CD) -> bool { + const bool ArgsMatch = !CD.RequiredArgs || CD.RequiredArgs == getNumArgs(); + const bool ParamsMatch = + !CD.RequiredParams || CD.RequiredParams == parameters().size(); + return ArgsMatch && ParamsMatch; + }; - if (const auto *RD = dyn_cast(Ctx)) { - if (RD->getName() == CD.QualifiedName[NumUnmatched - 1]) - --NumUnmatched; + const auto MatchQualifierSegments = [&CD](const Decl *D) -> bool { + const auto FindNextNamespaceOrRecord = + [](const DeclContext *Ctx) -> const DeclContext * { + while (Ctx && !isa(Ctx) && !isa(Ctx)) + Ctx = Ctx->getParent(); + return Ctx; + }; + + auto QualifierIt = CD.begin_qualifiers(); + const auto QualifierEndIt = CD.end_qualifiers(); + + // Match namespace and record names. Skip unrelated names if they don't + // match. + const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext()); + for (; Ctx && QualifierIt != QualifierEndIt; + Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) { + // If not matched just continue and try matching for the next one. + if (cast(Ctx)->getName() != *QualifierIt) continue; - } + ++QualifierIt; } - if (NumUnmatched > 0) - return false; - } + // If there are unmatched DeclContexts, none of them should be NamespaceDecl + // or RecordDecl. + // FIXME: It would break the return-value-guaranteed.cpp test since there + // the given struct is defined in an unexpected namespace. + // if (Ctx && !FindNextNamespaceOrRecord(Ctx->getParent())) + // return false; + + // We matched if we consumed all expected qualifier segments. + return QualifierIt == QualifierEndIt; + }; + + // Let's start matching... + if (!ExactMatchArgAndParamCounts(CD)) + return false; + + if (!MatchNameOnly(FD)) + return false; + + if (CD.QualifiedName.size() == 1) + return true; - return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) && - (!CD.RequiredParams || CD.RequiredParams == parameters().size()); + return MatchQualifierSegments(FD); } SVal CallEvent::getArgSVal(unsigned Index) const {