MTC updated this revision to Diff 161217.
MTC added a comment.

- rebase
- Since we have enhanced the ability of `CallDescription`, remove the helper 
method `isCalledOnStringObject()`.


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
@@ -359,11 +359,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
@@ -86,14 +86,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") {}
-
-  /// Check if the object of this member function call is a `basic_string`.
-  bool isCalledOnStringObject(const CXXInstanceCall *ICall) const;
+      : 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 called member function potentially invalidates
   /// pointers referring to the container object's inner buffer.
@@ -122,21 +128,6 @@
 
 } // end anonymous namespace
 
-bool InnerPointerChecker::isCalledOnStringObject(
-        const CXXInstanceCall *ICall) const {
-  const auto *ObjRegion =
-    dyn_cast_or_null<TypedValueRegion>(ICall->getCXXThisVal().getAsRegion());
-  if (!ObjRegion)
-    return false;
-
-  QualType ObjTy = ObjRegion->getValueType();
-  if (ObjTy.isNull())
-    return false;
-
-  CXXRecordDecl *Decl = ObjTy->getAsCXXRecordDecl();
-  return Decl && Decl->getName() == "basic_string";
-}
-
 bool InnerPointerChecker::isInvalidatingMemberFunction(
         const CallEvent &Call) const {
   if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
@@ -220,33 +211,31 @@
   ProgramStateRef State = C.getState();
 
   if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
-    if (isCalledOnStringObject(ICall)) {
-      const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
-              ICall->getCXXThisVal().getAsRegion());
-
-      if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
-        SVal RawPtr = Call.getReturnValue();
-        if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
-          // Start tracking this raw pointer by adding it to the set of symbols
-          // associated with this container object in the program state map.
-
-          PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
-          const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
-          PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
-          assert(C.wasInlined || !Set.contains(Sym));
-          Set = F.add(Set, Sym);
-
-          State = State->set<RawPtrMap>(ObjRegion, Set);
-          C.addTransition(State);
-        }
-        return;
+    const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
+        ICall->getCXXThisVal().getAsRegion());
+
+    if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
+      SVal RawPtr = Call.getReturnValue();
+      if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
+        // Start tracking this raw pointer by adding it to the set of symbols
+        // associated with this container object in the program state map.
+
+        PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
+        const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
+        PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
+        assert(C.wasInlined || !Set.contains(Sym));
+        Set = F.add(Set, Sym);
+
+        State = State->set<RawPtrMap>(ObjRegion, Set);
+        C.addTransition(State);
       }
+      return;
+    }
 
-      // Check [string.require] / second point.
-      if (isInvalidatingMemberFunction(Call)) {
-        markPtrSymbolsReleased(Call, State, ObjRegion, C);
-        return;
-      }
+    // Check [string.require] / second point.
+    if (isInvalidatingMemberFunction(Call)) {
+      markPtrSymbolsReleased(Call, State, ObjRegion, C);
+      return;
     }
   }
 
Index: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -80,24 +80,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