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

Reply via email to