MTC updated this revision to Diff 157499. MTC added a comment. @xazax.hun Thanks for your tips! After some investigation, `MatchFinder::match` just traverse one ASTNode, that means `match(namedDecl(HasNameMatcher()))` and `match(namedDecl(matchesName()))` both not traverse children. So there are three ways to match the specified AST node.
1. `match(namedDecl(HasNameMatcher()))` matches the full qualified name that contains template parameter and that's not what we want to see. 2. `match(namedDecl(matchesName()))` uses llvm regex to match the full qualified name. 3. Unwrap the declaration and match each layer, similar to `HasNameMatcher::matchesNodeFullFast()`. In this update, I use the third way to match the specified AST node. This is simpler than I thought. In addition, add a redundant constructor that is only used to construct a `CallDescription` with one name, this avoids the modification of the existing checker, like `BlockInCriticalSectionChecker.cpp`. Any suggestions? Repository: rC Clang https://reviews.llvm.org/D48027 Files: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp lib/StaticAnalyzer/Core/CallEvent.cpp
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<StringRef> QualifiedName = CD.QualifiedName; + QualifiedName.pop_back(); + for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) { + if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) { + if (!QualifiedName.empty() && ND->getName() == QualifiedName.back()) + QualifiedName.pop_back(); + continue; + } + + if (const auto *RD = dyn_cast<RecordDecl>(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()); } 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: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -79,24 +79,41 @@ 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<StringRef> QualifiedName; unsigned RequiredArgs; public: const static unsigned NoArgRequirement = std::numeric_limits<unsigned>::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<StringRef> QualifiedName, + unsigned RequiredArgs = NoArgRequirement) + : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {} + /// Constructs a CallDescription object. /// /// @param FuncName The name of the function that will be matched. /// /// @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(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement) - : FuncName(FuncName), RequiredArgs(RequiredArgs) {} + : CallDescription(std::vector<StringRef>({FuncName}), NoArgRequirement) { + } /// Get the name of the function that this object matches. - StringRef getFunctionName() const { return FuncName; } + StringRef getFunctionName() const { return QualifiedName.back(); } }; template<typename T = CallEvent>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits