Index: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -79,12 +79,28 @@ mutable IdentifierInfo *II = nullptr; mutable bool IsLookupDone = false; - StringRef FuncName; + // The list of the qualified names used to identify the specified CallEvent, + // e.g. "{a, b}" represent the qualified names, like "a::b". + std::vector QualifiedName; unsigned RequiredArgs; public: const static unsigned NoArgRequirement = std::numeric_limits::max(); + /// Constructs a CallDescription object. + /// + /// @param QualifiedName The list of the qualified names of the function that + /// will be matched. It does not require the user to provide the full list of + /// the qualified name. The more details provided, the more accurate the + /// matching. + /// + /// @param RequiredArgs The number of arguments that is expected to match a + /// call. Omit this parameter to match every occurrence of call with a given + /// name regardless the number of arguments. + CallDescription(std::vector QualifiedName, + unsigned RequiredArgs = NoArgRequirement) + : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {} + /// Constructs a CallDescription object. /// /// @param FuncName The name of the function that will be matched. @@ -93,10 +109,11 @@ /// call. Omit this parameter to match every occurrence of call with a given /// name regardless the number of arguments. CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement) - : FuncName(FuncName), RequiredArgs(RequiredArgs) {} + : CallDescription(std::vector({FuncName}), NoArgRequirement) { + } /// Get the name of the function that this object matches. - StringRef getFunctionName() const { return FuncName; } + StringRef getFunctionName() const { return QualifiedName.back(); } }; template Index: lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp +++ lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp @@ -85,11 +85,20 @@ }; InnerPointerChecker() - : AppendFn("append"), AssignFn("assign"), ClearFn("clear"), - CStrFn("c_str"), DataFn("data"), EraseFn("erase"), InsertFn("insert"), - PopBackFn("pop_back"), PushBackFn("push_back"), ReplaceFn("replace"), - ReserveFn("reserve"), ResizeFn("resize"), - ShrinkToFitFn("shrink_to_fit"), SwapFn("swap") {} + : AppendFn({"std", "basic_string", "append"}), + AssignFn({"std", "basic_string", "assign"}), + ClearFn({"std", "basic_string", "clear"}), + CStrFn({"std", "basic_string", "c_str"}), + DataFn({"std", "basic_string", "data"}), + EraseFn({"std", "basic_string", "erase"}), + InsertFn({"std", "basic_string", "insert"}), + PopBackFn({"std", "basic_string", "pop_back"}), + PushBackFn({"std", "basic_string", "push_back"}), + ReplaceFn({"std", "basic_string", "replace"}), + ReserveFn({"std", "basic_string", "reserve"}), + ResizeFn({"std", "basic_string", "resize"}), + ShrinkToFitFn({"std", "basic_string", "shrink_to_fit"}), + SwapFn({"std", "basic_string", "swap"}) {} /// Check whether the function called on the container object is a /// member function that potentially invalidates pointers referring @@ -148,10 +157,6 @@ if (!ObjRegion) return; - auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl(); - if (TypeDecl->getName() != "basic_string") - return; - ProgramStateRef State = C.getState(); if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { Index: lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- lib/StaticAnalyzer/Core/CallEvent.cpp +++ lib/StaticAnalyzer/Core/CallEvent.cpp @@ -256,11 +256,38 @@ return false; if (!CD.IsLookupDone) { CD.IsLookupDone = true; - CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); + CD.II = &getState()->getStateManager().getContext().Idents.get( + CD.getFunctionName()); } const IdentifierInfo *II = getCalleeIdentifier(); if (!II || II != CD.II) return false; + + const Decl *D = getDecl(); + // If CallDescription provides prefix names, use them to improve matching + // accuracy. + if (CD.QualifiedName.size() > 1 && D) { + const DeclContext *Ctx = D->getDeclContext(); + std::vector QualifiedName = CD.QualifiedName; + QualifiedName.pop_back(); + for (; Ctx && isa(Ctx); Ctx = Ctx->getParent()) { + if (const auto *ND = dyn_cast(Ctx)) { + if (!QualifiedName.empty() && ND->getName() == QualifiedName.back()) + QualifiedName.pop_back(); + continue; + } + + if (const auto *RD = dyn_cast(Ctx)) { + if (!QualifiedName.empty() && RD->getName() == QualifiedName.back()) + QualifiedName.pop_back(); + continue; + } + } + + if (!QualifiedName.empty()) + return false; + } + return (CD.RequiredArgs == CallDescription::NoArgRequirement || CD.RequiredArgs == getNumArgs()); }