[clang] 3ec7b91 - [analyzer][NFC] Refactor CallEvent::isCalled()

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 18 05:58:12 PDT 2021


Author: Balazs Benics
Date: 2021-10-18T14:57:24+02:00
New Revision: 3ec7b91141da4b3f4dce4964ca3ea7c3549584d2

URL: https://github.com/llvm/llvm-project/commit/3ec7b91141da4b3f4dce4964ca3ea7c3549584d2
DIFF: https://github.com/llvm/llvm-project/commit/3ec7b91141da4b3f4dce4964ca3ea7c3549584d2.diff

LOG: [analyzer][NFC] Refactor CallEvent::isCalled()

Refactor the code to make it more readable.

It will set up further changes, and improvements to this code in
subsequent patches.
This is a non-functional change.

Reviewed By: martong

Differential Revision: https://reviews.llvm.org/D111534

Added: 
    

Modified: 
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
    clang/lib/StaticAnalyzer/Core/CallEvent.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 060fff1a74071..e10e3509fe3d7 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -1237,9 +1237,7 @@ enum CallDescriptionFlags : int {
 /// arguments and the name of the function.
 class CallDescription {
   friend CallEvent;
-
-  mutable IdentifierInfo *II = nullptr;
-  mutable bool IsLookupDone = false;
+  mutable Optional<const IdentifierInfo *> II;
   // 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<const char *> QualifiedName;
@@ -1273,7 +1271,9 @@ class CallDescription {
                   Optional<size_t> RequiredParams = None)
       : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs),
         RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
-        Flags(Flags) {}
+        Flags(Flags) {
+    assert(!QualifiedName.empty());
+  }
 
   /// Construct a CallDescription with default flags.
   CallDescription(ArrayRef<const char *> QualifiedName,
@@ -1283,6 +1283,17 @@ class CallDescription {
 
   /// Get the name of the function that this object matches.
   StringRef getFunctionName() const { return QualifiedName.back(); }
+
+  /// Get the qualified name parts in reversed order.
+  /// E.g. { "std", "vector", "data" } -> "vector", "std"
+  auto begin_qualified_name_parts() const {
+    return std::next(QualifiedName.rbegin());
+  }
+  auto end_qualified_name_parts() const { return QualifiedName.rend(); }
+
+  /// It's false, if and only if we expect a single identifier, such as
+  /// `getenv`. It's true for `std::swap`, or `my::detail::container::data`.
+  bool hasQualifiedNameParts() const { return QualifiedName.size() > 1; }
 };
 
 /// An immutable map from CallDescriptions to arbitrary data. Provides a unified

diff  --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 9a95921b64c3b..ec44bcf5b27ca 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -307,10 +307,7 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
   if (getKind() == CE_ObjCMessage)
     return false;
 
-  const IdentifierInfo *II = getCalleeIdentifier();
-  if (!II)
-    return false;
-  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
+  const auto *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
   if (!FD)
     return false;
 
@@ -320,44 +317,69 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
            (!CD.RequiredParams || CD.RequiredParams <= parameters().size());
   }
 
-  if (!CD.IsLookupDone) {
-    CD.IsLookupDone = true;
+  if (!CD.II.hasValue()) {
     CD.II = &getState()->getStateManager().getContext().Idents.get(
         CD.getFunctionName());
   }
 
-  if (II != CD.II)
-    return false;
+  const auto MatchNameOnly = [](const CallDescription &CD,
+                                const NamedDecl *ND) -> bool {
+    DeclarationName Name = ND->getDeclName();
+    if (const auto *II = Name.getAsIdentifierInfo())
+      return II == CD.II.getValue(); // 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<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
-      if (NumUnmatched == 0)
-        break;
+    // Simply report mismatch for:
+    // C++ overloaded operators, constructors, destructors, etc.
+    return false;
+  };
 
-      if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
-        if (ND->getName() == CD.QualifiedName[NumUnmatched - 1])
-          --NumUnmatched;
-        continue;
-      }
+  const auto ExactMatchArgAndParamCounts =
+      [](const CallEvent &Call, const CallDescription &CD) -> bool {
+    const bool ArgsMatch =
+        !CD.RequiredArgs || CD.RequiredArgs == Call.getNumArgs();
+    const bool ParamsMatch =
+        !CD.RequiredParams || CD.RequiredParams == Call.parameters().size();
+    return ArgsMatch && ParamsMatch;
+  };
 
-      if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) {
-        if (RD->getName() == CD.QualifiedName[NumUnmatched - 1])
-          --NumUnmatched;
+  const auto MatchQualifiedNameParts = [](const CallDescription &CD,
+                                          const Decl *D) -> bool {
+    const auto FindNextNamespaceOrRecord =
+        [](const DeclContext *Ctx) -> const DeclContext * {
+      while (Ctx && !isa<NamespaceDecl, RecordDecl>(Ctx))
+        Ctx = Ctx->getParent();
+      return Ctx;
+    };
+
+    auto QualifierPartsIt = CD.begin_qualified_name_parts();
+    const auto QualifierPartsEndIt = CD.end_qualified_name_parts();
+
+    // Match namespace and record names. Skip unrelated names if they don't
+    // match.
+    const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
+    for (; Ctx && QualifierPartsIt != QualifierPartsEndIt;
+         Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
+      // If not matched just continue and try matching for the next one.
+      if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
         continue;
-      }
+      ++QualifierPartsIt;
     }
 
-    if (NumUnmatched > 0)
-      return false;
-  }
+    // We matched if we consumed all expected qualifier segments.
+    return QualifierPartsIt == QualifierPartsEndIt;
+  };
+
+  // Let's start matching...
+  if (!ExactMatchArgAndParamCounts(*this, CD))
+    return false;
+
+  if (!MatchNameOnly(CD, FD))
+    return false;
+
+  if (!CD.hasQualifiedNameParts())
+    return true;
 
-  return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) &&
-         (!CD.RequiredParams || CD.RequiredParams == parameters().size());
+  return MatchQualifiedNameParts(CD, FD);
 }
 
 SVal CallEvent::getArgSVal(unsigned Index) const {


        


More information about the cfe-commits mailing list