[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #124554)

2025-02-03 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska closed 
https://github.com/llvm/llvm-project/pull/124554
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-02-03 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska ready_for_review 
https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-02-03 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska created 
https://github.com/llvm/llvm-project/pull/125492

None

>From 54c7b3c1fb149b82c26927d0fd831d8786f70ac3 Mon Sep 17 00:00:00 2001
From: Ivana Ivanovska 
Date: Mon, 2 Dec 2024 14:17:06 +
Subject: [PATCH] Optimize -Wunsafe-buffer-usage.

---
 clang/lib/Analysis/UnsafeBufferUsage.cpp | 1427 ++
 1 file changed, 906 insertions(+), 521 deletions(-)

diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index c064aa30e8aedc..4520d28d9e9452 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -8,30 +8,32 @@
 
 #include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/FormatString.h"
+#include "clang/AST/ParentMapContext.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
-#include 
 #include 
 #include 
+#include 
 #include 
 
 using namespace llvm;
 using namespace clang;
-using namespace ast_matchers;
 
 #ifndef NDEBUG
 namespace {
@@ -68,7 +70,7 @@ static std::string getDREAncestorString(const DeclRefExpr 
*DRE,
 
 if (StParents.size() > 1)
   return "unavailable due to multiple parents";
-if (StParents.size() == 0)
+if (StParents.empty())
   break;
 St = StParents.begin()->get();
 if (St)
@@ -76,10 +78,39 @@ static std::string getDREAncestorString(const DeclRefExpr 
*DRE,
   } while (St);
   return SS.str();
 }
+
 } // namespace
 #endif /* NDEBUG */
 
-namespace clang::ast_matchers {
+namespace {
+// Using a custom matcher instead of ASTMatchers to achieve better performance.
+class FastMatcher {
+public:
+  virtual bool matches(const DynTypedNode &DynNode, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler) = 0;
+  virtual ~FastMatcher() = default;
+};
+
+class MatchResult {
+
+public:
+  template  const T *getNodeAs(StringRef ID) const {
+auto It = Nodes.find(std::string(ID));
+if (It == Nodes.end()) {
+  return nullptr;
+}
+return It->second.get();
+  }
+
+  void addNode(StringRef ID, const DynTypedNode &Node) {
+Nodes[std::string(ID)] = Node;
+  }
+
+private:
+  llvm::StringMap Nodes;
+};
+} // namespace
+
 // A `RecursiveASTVisitor` that traverses all descendants of a given node "n"
 // except for those belonging to a different callable of "n".
 class MatchDescendantVisitor : public DynamicRecursiveASTVisitor {
@@ -87,13 +118,11 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
   // Creates an AST visitor that matches `Matcher` on all
   // descendants of a given node "n" except for the ones
   // belonging to a different callable of "n".
-  MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher,
- internal::ASTMatchFinder *Finder,
- internal::BoundNodesTreeBuilder *Builder,
- internal::ASTMatchFinder::BindKind Bind,
+  MatchDescendantVisitor(FastMatcher &Matcher, bool FindAll,
  const bool ignoreUnevaluatedContext)
-  : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
-Matches(false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {
+  : Matcher(&Matcher), FindAll(FindAll), Matches(false),
+ignoreUnevaluatedContext(ignoreUnevaluatedContext),
+ActiveASTContext(nullptr), Handler(nullptr) {
 ShouldVisitTemplateInstantiations = true;
 ShouldVisitImplicitCode = false; // TODO: let's ignore implicit code for 
now
   }
@@ -104,7 +133,6 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 Matches = false;
 if (const Stmt *StmtNode = DynNode.get()) {
   TraverseStmt(const_cast(StmtNode));
-  *Builder = ResultBindings;
   return Matches;
 }
 return false;
@@ -186,106 +214,212 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' 

[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-02-03 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska edited 
https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #124554)

2025-01-31 Thread Ivana Ivanovska via cfe-commits


@@ -68,32 +70,60 @@ static std::string getDREAncestorString(const DeclRefExpr 
*DRE,
 
 if (StParents.size() > 1)
   return "unavailable due to multiple parents";
-if (StParents.size() == 0)
+if (StParents.empty())
   break;
 St = StParents.begin()->get();
 if (St)
   SS << " ==> ";
   } while (St);
   return SS.str();
 }
+
 } // namespace
 #endif /* NDEBUG */
 
-namespace clang::ast_matchers {
+namespace {
+// Using a custom matcher instead of ASTMatchers to achieve better performance.
+class FastMatcher {
+public:
+  virtual bool matches(const DynTypedNode &DynNode, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler) = 0;
+  virtual ~FastMatcher() = default;
+};
+
+class MatchResult {
+
+public:
+  template  const T *getNodeAs(StringRef ID) const {
+auto It = Nodes.find(std::string(ID));
+if (It == Nodes.end()) {
+  return nullptr;
+}
+return It->second.get();
+  }
+
+  void addNode(StringRef ID, const DynTypedNode &Node) {
+Nodes[std::string(ID)] = Node;
+  }
+
+private:
+  llvm::StringMap
+  Nodes; // DynTypedNode needed to store different types of Nodes, not
+ // necessarily sharing the same base.
+};
+} // namespace
+
 // A `RecursiveASTVisitor` that traverses all descendants of a given node "n"
 // except for those belonging to a different callable of "n".
 class MatchDescendantVisitor : public DynamicRecursiveASTVisitor {
 public:
   // Creates an AST visitor that matches `Matcher` on all
   // descendants of a given node "n" except for the ones
   // belonging to a different callable of "n".
-  MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher,
- internal::ASTMatchFinder *Finder,
- internal::BoundNodesTreeBuilder *Builder,
- internal::ASTMatchFinder::BindKind Bind,
+  MatchDescendantVisitor(FastMatcher &Matcher, bool FindAll,
  const bool ignoreUnevaluatedContext)
-  : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
-Matches(false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {
+  : Matcher(&Matcher), FindAll(FindAll), Matches(false),
+ignoreUnevaluatedContext(ignoreUnevaluatedContext) {

ivanaivanovska wrote:

Done.

https://github.com/llvm/llvm-project/pull/124554
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #124554)

2025-01-31 Thread Ivana Ivanovska via cfe-commits


@@ -68,32 +70,60 @@ static std::string getDREAncestorString(const DeclRefExpr 
*DRE,
 
 if (StParents.size() > 1)
   return "unavailable due to multiple parents";
-if (StParents.size() == 0)
+if (StParents.empty())
   break;
 St = StParents.begin()->get();
 if (St)
   SS << " ==> ";
   } while (St);
   return SS.str();
 }
+
 } // namespace
 #endif /* NDEBUG */
 
-namespace clang::ast_matchers {
+namespace {
+// Using a custom matcher instead of ASTMatchers to achieve better performance.
+class FastMatcher {
+public:
+  virtual bool matches(const DynTypedNode &DynNode, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler) = 0;
+  virtual ~FastMatcher() = default;
+};
+
+class MatchResult {
+
+public:
+  template  const T *getNodeAs(StringRef ID) const {
+auto It = Nodes.find(std::string(ID));
+if (It == Nodes.end()) {
+  return nullptr;
+}
+return It->second.get();
+  }
+
+  void addNode(StringRef ID, const DynTypedNode &Node) {
+Nodes[std::string(ID)] = Node;
+  }
+
+private:
+  llvm::StringMap
+  Nodes; // DynTypedNode needed to store different types of Nodes, not

ivanaivanovska wrote:

Done.

https://github.com/llvm/llvm-project/pull/124554
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #124554)

2025-01-31 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska edited 
https://github.com/llvm/llvm-project/pull/124554
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-02-06 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska updated 
https://github.com/llvm/llvm-project/pull/125492

>From 54c7b3c1fb149b82c26927d0fd831d8786f70ac3 Mon Sep 17 00:00:00 2001
From: Ivana Ivanovska 
Date: Mon, 2 Dec 2024 14:17:06 +
Subject: [PATCH 1/2] Optimize -Wunsafe-buffer-usage.

---
 clang/lib/Analysis/UnsafeBufferUsage.cpp | 1427 ++
 1 file changed, 906 insertions(+), 521 deletions(-)

diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index c064aa30e8aedc6..4520d28d9e94522 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -8,30 +8,32 @@
 
 #include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/FormatString.h"
+#include "clang/AST/ParentMapContext.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
-#include 
 #include 
 #include 
+#include 
 #include 
 
 using namespace llvm;
 using namespace clang;
-using namespace ast_matchers;
 
 #ifndef NDEBUG
 namespace {
@@ -68,7 +70,7 @@ static std::string getDREAncestorString(const DeclRefExpr 
*DRE,
 
 if (StParents.size() > 1)
   return "unavailable due to multiple parents";
-if (StParents.size() == 0)
+if (StParents.empty())
   break;
 St = StParents.begin()->get();
 if (St)
@@ -76,10 +78,39 @@ static std::string getDREAncestorString(const DeclRefExpr 
*DRE,
   } while (St);
   return SS.str();
 }
+
 } // namespace
 #endif /* NDEBUG */
 
-namespace clang::ast_matchers {
+namespace {
+// Using a custom matcher instead of ASTMatchers to achieve better performance.
+class FastMatcher {
+public:
+  virtual bool matches(const DynTypedNode &DynNode, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler) = 0;
+  virtual ~FastMatcher() = default;
+};
+
+class MatchResult {
+
+public:
+  template  const T *getNodeAs(StringRef ID) const {
+auto It = Nodes.find(std::string(ID));
+if (It == Nodes.end()) {
+  return nullptr;
+}
+return It->second.get();
+  }
+
+  void addNode(StringRef ID, const DynTypedNode &Node) {
+Nodes[std::string(ID)] = Node;
+  }
+
+private:
+  llvm::StringMap Nodes;
+};
+} // namespace
+
 // A `RecursiveASTVisitor` that traverses all descendants of a given node "n"
 // except for those belonging to a different callable of "n".
 class MatchDescendantVisitor : public DynamicRecursiveASTVisitor {
@@ -87,13 +118,11 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
   // Creates an AST visitor that matches `Matcher` on all
   // descendants of a given node "n" except for the ones
   // belonging to a different callable of "n".
-  MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher,
- internal::ASTMatchFinder *Finder,
- internal::BoundNodesTreeBuilder *Builder,
- internal::ASTMatchFinder::BindKind Bind,
+  MatchDescendantVisitor(FastMatcher &Matcher, bool FindAll,
  const bool ignoreUnevaluatedContext)
-  : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
-Matches(false), ignoreUnevaluatedContext(ignoreUnevaluatedContext) {
+  : Matcher(&Matcher), FindAll(FindAll), Matches(false),
+ignoreUnevaluatedContext(ignoreUnevaluatedContext),
+ActiveASTContext(nullptr), Handler(nullptr) {
 ShouldVisitTemplateInstantiations = true;
 ShouldVisitImplicitCode = false; // TODO: let's ignore implicit code for 
now
   }
@@ -104,7 +133,6 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 Matches = false;
 if (const Stmt *StmtNode = DynNode.get()) {
   TraverseStmt(const_cast(StmtNode));
-  *Builder = ResultBindings;
   return Matches;
 }
 return false;
@@ -186,106 +214,212 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' 

[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-02-07 Thread Ivana Ivanovska via cfe-commits

ivanaivanovska wrote:

> @ivanaivanovska @ilya-biryukov One PR is fine. I will look at it.

@ziqingluo-90 Thank you!

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #124554)

2025-01-30 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska updated 
https://github.com/llvm/llvm-project/pull/124554

504 Gateway Time-out
The server didn't respond in time.


___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -186,106 +212,208 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
   template  bool match(const T &Node) {
-internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
-
-if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
-  ResultBindings.addMatch(RecursiveBuilder);
+if (Matcher->matches(DynTypedNode::create(Node), *ActiveASTContext,
+ *Handler)) {
   Matches = true;
-  if (Bind != internal::ASTMatchFinder::BK_All)
+  if (!FindAll)
 return false; // Abort as soon as a match is found.
 }
 return true;
   }
 
-  const internal::DynTypedMatcher *const Matcher;
-  internal::ASTMatchFinder *const Finder;
-  internal::BoundNodesTreeBuilder *const Builder;
-  internal::BoundNodesTreeBuilder ResultBindings;
-  const internal::ASTMatchFinder::BindKind Bind;
+  FastMatcher *const Matcher;
+  // When true, finds all matches. When false, finds the first match and stops.
+  const bool FindAll;
   bool Matches;
   bool ignoreUnevaluatedContext;
+  ASTContext *ActiveASTContext;
+  const UnsafeBufferUsageHandler *Handler;
 };
 
 // Because we're dealing with raw pointers, let's define what we mean by that.
-static auto hasPointerType() {
-  return hasType(hasCanonicalType(pointerType()));
+static bool hasPointerType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-static auto hasArrayType() { return hasType(hasCanonicalType(arrayType())); }
-
-AST_MATCHER_P(Stmt, forEachDescendantEvaluatedStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
-
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- true);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static bool hasArrayType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-AST_MATCHER_P(Stmt, forEachDescendantStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
+static void
+forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler,
+   FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/true);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
+}
 
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- false);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler &Handler,
+  FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/false);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
 }
 
 // Matches a `Stmt` node iff the node is in a safe-buffer opt-out region
-AST_MATCHER_P(Stmt, notInSafeBufferOptOut, const UnsafeBufferUsageHandler *,
-  Handler) {
+static bool notInSafeBufferOptOut(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return !Handler->isSafeBufferOptOut(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeBufferInContainer,
-  const UnsafeBufferUsageHandler *, Handler) {
+static bool
+ignoreUnsafeBufferInContainer(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return Handler->ignoreUnsafeBufferInContainer(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeLibcCall, const UnsafeBufferUsageHandler *,
-  Handler) {
-  if (Finder->getASTContext().getLangOpts().CPlusPlus)
+static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node,
+ const UnsafeBufferUsageHandler *Handler) {
+  if (Ctx.getLangOpts().CPlusPlus)
 return Handler->ignoreUnsafeBufferInLibcCall(Node.getBeginLoc());
   return true; /* Only warn about libc calls for C++ */
 }
 
-AST_MATCHER_P(CastExpr, castSubExpr, internal::Matcher, innerMatcher) {
-  return innerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
+// Finds any exp

[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -186,106 +212,208 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
   template  bool match(const T &Node) {
-internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
-
-if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
-  ResultBindings.addMatch(RecursiveBuilder);
+if (Matcher->matches(DynTypedNode::create(Node), *ActiveASTContext,
+ *Handler)) {
   Matches = true;
-  if (Bind != internal::ASTMatchFinder::BK_All)
+  if (!FindAll)
 return false; // Abort as soon as a match is found.
 }
 return true;
   }
 
-  const internal::DynTypedMatcher *const Matcher;
-  internal::ASTMatchFinder *const Finder;
-  internal::BoundNodesTreeBuilder *const Builder;
-  internal::BoundNodesTreeBuilder ResultBindings;
-  const internal::ASTMatchFinder::BindKind Bind;
+  FastMatcher *const Matcher;
+  // When true, finds all matches. When false, finds the first match and stops.
+  const bool FindAll;
   bool Matches;
   bool ignoreUnevaluatedContext;
+  ASTContext *ActiveASTContext;
+  const UnsafeBufferUsageHandler *Handler;
 };
 
 // Because we're dealing with raw pointers, let's define what we mean by that.
-static auto hasPointerType() {
-  return hasType(hasCanonicalType(pointerType()));
+static bool hasPointerType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-static auto hasArrayType() { return hasType(hasCanonicalType(arrayType())); }
-
-AST_MATCHER_P(Stmt, forEachDescendantEvaluatedStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
-
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- true);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static bool hasArrayType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-AST_MATCHER_P(Stmt, forEachDescendantStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
+static void
+forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler,
+   FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/true);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
+}
 
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- false);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler &Handler,
+  FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/false);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
 }
 
 // Matches a `Stmt` node iff the node is in a safe-buffer opt-out region
-AST_MATCHER_P(Stmt, notInSafeBufferOptOut, const UnsafeBufferUsageHandler *,
-  Handler) {
+static bool notInSafeBufferOptOut(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return !Handler->isSafeBufferOptOut(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeBufferInContainer,
-  const UnsafeBufferUsageHandler *, Handler) {
+static bool
+ignoreUnsafeBufferInContainer(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return Handler->ignoreUnsafeBufferInContainer(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeLibcCall, const UnsafeBufferUsageHandler *,
-  Handler) {
-  if (Finder->getASTContext().getLangOpts().CPlusPlus)
+static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node,
+ const UnsafeBufferUsageHandler *Handler) {
+  if (Ctx.getLangOpts().CPlusPlus)
 return Handler->ignoreUnsafeBufferInLibcCall(Node.getBeginLoc());
   return true; /* Only warn about libc calls for C++ */
 }
 
-AST_MATCHER_P(CastExpr, castSubExpr, internal::Matcher, innerMatcher) {
-  return innerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
+// Finds any exp

[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -186,106 +212,208 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
   template  bool match(const T &Node) {
-internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
-
-if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
-  ResultBindings.addMatch(RecursiveBuilder);
+if (Matcher->matches(DynTypedNode::create(Node), *ActiveASTContext,
+ *Handler)) {
   Matches = true;
-  if (Bind != internal::ASTMatchFinder::BK_All)
+  if (!FindAll)
 return false; // Abort as soon as a match is found.
 }
 return true;
   }
 
-  const internal::DynTypedMatcher *const Matcher;
-  internal::ASTMatchFinder *const Finder;
-  internal::BoundNodesTreeBuilder *const Builder;
-  internal::BoundNodesTreeBuilder ResultBindings;
-  const internal::ASTMatchFinder::BindKind Bind;
+  FastMatcher *const Matcher;
+  // When true, finds all matches. When false, finds the first match and stops.
+  const bool FindAll;
   bool Matches;
   bool ignoreUnevaluatedContext;
+  ASTContext *ActiveASTContext;
+  const UnsafeBufferUsageHandler *Handler;
 };
 
 // Because we're dealing with raw pointers, let's define what we mean by that.
-static auto hasPointerType() {
-  return hasType(hasCanonicalType(pointerType()));
+static bool hasPointerType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-static auto hasArrayType() { return hasType(hasCanonicalType(arrayType())); }
-
-AST_MATCHER_P(Stmt, forEachDescendantEvaluatedStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
-
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- true);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static bool hasArrayType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-AST_MATCHER_P(Stmt, forEachDescendantStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
+static void
+forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler,
+   FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/true);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
+}
 
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- false);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler &Handler,
+  FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/false);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
 }
 
 // Matches a `Stmt` node iff the node is in a safe-buffer opt-out region
-AST_MATCHER_P(Stmt, notInSafeBufferOptOut, const UnsafeBufferUsageHandler *,
-  Handler) {
+static bool notInSafeBufferOptOut(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return !Handler->isSafeBufferOptOut(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeBufferInContainer,
-  const UnsafeBufferUsageHandler *, Handler) {
+static bool
+ignoreUnsafeBufferInContainer(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return Handler->ignoreUnsafeBufferInContainer(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeLibcCall, const UnsafeBufferUsageHandler *,
-  Handler) {
-  if (Finder->getASTContext().getLangOpts().CPlusPlus)
+static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node,
+ const UnsafeBufferUsageHandler *Handler) {
+  if (Ctx.getLangOpts().CPlusPlus)
 return Handler->ignoreUnsafeBufferInLibcCall(Node.getBeginLoc());
   return true; /* Only warn about libc calls for C++ */
 }
 
-AST_MATCHER_P(CastExpr, castSubExpr, internal::Matcher, innerMatcher) {
-  return innerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
+// Finds any exp

[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -186,106 +212,208 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
   template  bool match(const T &Node) {
-internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
-
-if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
-  ResultBindings.addMatch(RecursiveBuilder);
+if (Matcher->matches(DynTypedNode::create(Node), *ActiveASTContext,
+ *Handler)) {
   Matches = true;
-  if (Bind != internal::ASTMatchFinder::BK_All)
+  if (!FindAll)
 return false; // Abort as soon as a match is found.
 }
 return true;
   }
 
-  const internal::DynTypedMatcher *const Matcher;
-  internal::ASTMatchFinder *const Finder;
-  internal::BoundNodesTreeBuilder *const Builder;
-  internal::BoundNodesTreeBuilder ResultBindings;
-  const internal::ASTMatchFinder::BindKind Bind;
+  FastMatcher *const Matcher;
+  // When true, finds all matches. When false, finds the first match and stops.
+  const bool FindAll;
   bool Matches;
   bool ignoreUnevaluatedContext;
+  ASTContext *ActiveASTContext;
+  const UnsafeBufferUsageHandler *Handler;
 };
 
 // Because we're dealing with raw pointers, let's define what we mean by that.
-static auto hasPointerType() {
-  return hasType(hasCanonicalType(pointerType()));
+static bool hasPointerType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-static auto hasArrayType() { return hasType(hasCanonicalType(arrayType())); }
-
-AST_MATCHER_P(Stmt, forEachDescendantEvaluatedStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
-
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- true);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static bool hasArrayType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-AST_MATCHER_P(Stmt, forEachDescendantStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
+static void
+forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler,
+   FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/true);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
+}
 
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- false);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler &Handler,
+  FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/false);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);
+  Visitor.findMatch(DynTypedNode::create(*S));
 }
 
 // Matches a `Stmt` node iff the node is in a safe-buffer opt-out region
-AST_MATCHER_P(Stmt, notInSafeBufferOptOut, const UnsafeBufferUsageHandler *,
-  Handler) {
+static bool notInSafeBufferOptOut(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return !Handler->isSafeBufferOptOut(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeBufferInContainer,
-  const UnsafeBufferUsageHandler *, Handler) {
+static bool
+ignoreUnsafeBufferInContainer(const Stmt &Node,
+  const UnsafeBufferUsageHandler *Handler) {
   return Handler->ignoreUnsafeBufferInContainer(Node.getBeginLoc());
 }
 
-AST_MATCHER_P(Stmt, ignoreUnsafeLibcCall, const UnsafeBufferUsageHandler *,
-  Handler) {
-  if (Finder->getASTContext().getLangOpts().CPlusPlus)
+static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node,
+ const UnsafeBufferUsageHandler *Handler) {
+  if (Ctx.getLangOpts().CPlusPlus)
 return Handler->ignoreUnsafeBufferInLibcCall(Node.getBeginLoc());
   return true; /* Only warn about libc calls for C++ */
 }
 
-AST_MATCHER_P(CastExpr, castSubExpr, internal::Matcher, innerMatcher) {
-  return innerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
+// Finds any exp

[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -1561,56 +1821,70 @@ class UnsafeLibcFunctionCallGadget : public 
WarningGadget {
   } WarnedFunKind = OTHERS;
 
 public:
-  UnsafeLibcFunctionCallGadget(const MatchFinder::MatchResult &Result)
+  UnsafeLibcFunctionCallGadget(const MatchResult &Result)
   : WarningGadget(Kind::UnsafeLibcFunctionCall),
-Call(Result.Nodes.getNodeAs(Tag)) {
-if (Result.Nodes.getNodeAs(UnsafeSprintfTag))
+Call(Result.getNodeAs(Tag)) {
+if (Result.getNodeAs(UnsafeSprintfTag))
   WarnedFunKind = SPRINTF;
-else if (auto *E = Result.Nodes.getNodeAs(UnsafeStringTag)) {
+else if (auto *E = Result.getNodeAs(UnsafeStringTag)) {
   WarnedFunKind = STRING;
   UnsafeArg = E;
-} else if (Result.Nodes.getNodeAs(UnsafeSizedByTag)) {
+} else if (Result.getNodeAs(UnsafeSizedByTag)) {
   WarnedFunKind = SIZED_BY;
   UnsafeArg = Call->getArg(0);
-} else if (Result.Nodes.getNodeAs(UnsafeVaListTag))
+} else if (Result.getNodeAs(UnsafeVaListTag))
   WarnedFunKind = VA_LIST;
   }
 
-  static Matcher matcher(const UnsafeBufferUsageHandler *Handler) {
-return stmt(unless(ignoreUnsafeLibcCall(Handler)),
-  anyOf(
-callExpr(
-callee(functionDecl(anyOf(
-// Match a predefined unsafe libc
-// function:
-functionDecl(libc_func_matchers::isPredefinedUnsafeLibcFunc()),
-// Match a call to one of the `v*printf` functions
-// taking va-list, which cannot be checked at
-// compile-time:
-functionDecl(libc_func_matchers::isUnsafeVaListPrintfFunc())
-.bind(UnsafeVaListTag),
-// Match a call to a `sprintf` function, which is never
-// safe:
-functionDecl(libc_func_matchers::isUnsafeSprintfFunc())
-.bind(UnsafeSprintfTag,
-//  (unless the call has a sole string literal argument):
-unless(
-allOf(hasArgument(0, expr(stringLiteral())), hasNumArgs(1,
-
-// The following two cases require checking against actual
-// arguments of the call:
-
-// Match a call to an `snprintf` function. And first two
-// arguments of the call (that describe a buffer) are not in
-// safe patterns:
-
callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
- libc_func_matchers::hasUnsafeSnprintfBuffer())
-.bind(UnsafeSizedByTag),
-// Match a call to a `printf` function, which can be safe if
-// all arguments are null-terminated:
-
callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
- libc_func_matchers::hasUnsafePrintfStringArg(
- expr().bind(UnsafeStringTag);
+  static bool matches(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler *Handler,
+  MatchResult &Result) {
+if (ignoreUnsafeLibcCall(Ctx, *S, Handler))
+  return false;
+auto *CE = dyn_cast(S);
+if (!CE || !CE->getDirectCallee())
+  return false;
+const auto *FD = dyn_cast(CE->getDirectCallee());
+if (!FD)
+  return false;
+auto isSingleStringLiteralArg = false;
+if (CE->getNumArgs() == 1) {
+  const auto *const Arg = CE->getArg(0);
+  if (isa(Arg) && !Arg->children().empty()) {
+isSingleStringLiteralArg =
+isa(*Arg->children().begin());
+  }
+}
+if (!isSingleStringLiteralArg) { // (unless the call has a sole string

ivanaivanovska wrote:

Done.

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -1561,56 +1821,70 @@ class UnsafeLibcFunctionCallGadget : public 
WarningGadget {
   } WarnedFunKind = OTHERS;
 
 public:
-  UnsafeLibcFunctionCallGadget(const MatchFinder::MatchResult &Result)
+  UnsafeLibcFunctionCallGadget(const MatchResult &Result)
   : WarningGadget(Kind::UnsafeLibcFunctionCall),
-Call(Result.Nodes.getNodeAs(Tag)) {
-if (Result.Nodes.getNodeAs(UnsafeSprintfTag))
+Call(Result.getNodeAs(Tag)) {
+if (Result.getNodeAs(UnsafeSprintfTag))
   WarnedFunKind = SPRINTF;
-else if (auto *E = Result.Nodes.getNodeAs(UnsafeStringTag)) {
+else if (auto *E = Result.getNodeAs(UnsafeStringTag)) {
   WarnedFunKind = STRING;
   UnsafeArg = E;
-} else if (Result.Nodes.getNodeAs(UnsafeSizedByTag)) {
+} else if (Result.getNodeAs(UnsafeSizedByTag)) {
   WarnedFunKind = SIZED_BY;
   UnsafeArg = Call->getArg(0);
-} else if (Result.Nodes.getNodeAs(UnsafeVaListTag))
+} else if (Result.getNodeAs(UnsafeVaListTag))
   WarnedFunKind = VA_LIST;
   }
 
-  static Matcher matcher(const UnsafeBufferUsageHandler *Handler) {
-return stmt(unless(ignoreUnsafeLibcCall(Handler)),
-  anyOf(
-callExpr(
-callee(functionDecl(anyOf(
-// Match a predefined unsafe libc
-// function:
-functionDecl(libc_func_matchers::isPredefinedUnsafeLibcFunc()),
-// Match a call to one of the `v*printf` functions
-// taking va-list, which cannot be checked at
-// compile-time:
-functionDecl(libc_func_matchers::isUnsafeVaListPrintfFunc())
-.bind(UnsafeVaListTag),
-// Match a call to a `sprintf` function, which is never
-// safe:
-functionDecl(libc_func_matchers::isUnsafeSprintfFunc())
-.bind(UnsafeSprintfTag,
-//  (unless the call has a sole string literal argument):
-unless(
-allOf(hasArgument(0, expr(stringLiteral())), hasNumArgs(1,
-
-// The following two cases require checking against actual
-// arguments of the call:
-
-// Match a call to an `snprintf` function. And first two
-// arguments of the call (that describe a buffer) are not in
-// safe patterns:
-
callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
- libc_func_matchers::hasUnsafeSnprintfBuffer())
-.bind(UnsafeSizedByTag),
-// Match a call to a `printf` function, which can be safe if
-// all arguments are null-terminated:
-
callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
- libc_func_matchers::hasUnsafePrintfStringArg(
- expr().bind(UnsafeStringTag);
+  static bool matches(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler *Handler,
+  MatchResult &Result) {
+if (ignoreUnsafeLibcCall(Ctx, *S, Handler))
+  return false;
+auto *CE = dyn_cast(S);
+if (!CE || !CE->getDirectCallee())
+  return false;
+const auto *FD = dyn_cast(CE->getDirectCallee());
+if (!FD)
+  return false;
+auto isSingleStringLiteralArg = false;
+if (CE->getNumArgs() == 1) {
+  const auto *const Arg = CE->getArg(0);
+  if (isa(Arg) && !Arg->children().empty()) {
+isSingleStringLiteralArg =
+isa(*Arg->children().begin());

ivanaivanovska wrote:

Fixed. 

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-07 Thread Ivana Ivanovska via cfe-commits


@@ -1561,56 +1821,70 @@ class UnsafeLibcFunctionCallGadget : public 
WarningGadget {
   } WarnedFunKind = OTHERS;
 
 public:
-  UnsafeLibcFunctionCallGadget(const MatchFinder::MatchResult &Result)
+  UnsafeLibcFunctionCallGadget(const MatchResult &Result)
   : WarningGadget(Kind::UnsafeLibcFunctionCall),
-Call(Result.Nodes.getNodeAs(Tag)) {
-if (Result.Nodes.getNodeAs(UnsafeSprintfTag))
+Call(Result.getNodeAs(Tag)) {
+if (Result.getNodeAs(UnsafeSprintfTag))
   WarnedFunKind = SPRINTF;
-else if (auto *E = Result.Nodes.getNodeAs(UnsafeStringTag)) {
+else if (auto *E = Result.getNodeAs(UnsafeStringTag)) {
   WarnedFunKind = STRING;
   UnsafeArg = E;
-} else if (Result.Nodes.getNodeAs(UnsafeSizedByTag)) {
+} else if (Result.getNodeAs(UnsafeSizedByTag)) {
   WarnedFunKind = SIZED_BY;
   UnsafeArg = Call->getArg(0);
-} else if (Result.Nodes.getNodeAs(UnsafeVaListTag))
+} else if (Result.getNodeAs(UnsafeVaListTag))
   WarnedFunKind = VA_LIST;
   }
 
-  static Matcher matcher(const UnsafeBufferUsageHandler *Handler) {
-return stmt(unless(ignoreUnsafeLibcCall(Handler)),
-  anyOf(
-callExpr(
-callee(functionDecl(anyOf(
-// Match a predefined unsafe libc
-// function:
-functionDecl(libc_func_matchers::isPredefinedUnsafeLibcFunc()),
-// Match a call to one of the `v*printf` functions
-// taking va-list, which cannot be checked at
-// compile-time:
-functionDecl(libc_func_matchers::isUnsafeVaListPrintfFunc())
-.bind(UnsafeVaListTag),
-// Match a call to a `sprintf` function, which is never
-// safe:
-functionDecl(libc_func_matchers::isUnsafeSprintfFunc())
-.bind(UnsafeSprintfTag,
-//  (unless the call has a sole string literal argument):
-unless(
-allOf(hasArgument(0, expr(stringLiteral())), hasNumArgs(1,
-
-// The following two cases require checking against actual
-// arguments of the call:
-
-// Match a call to an `snprintf` function. And first two
-// arguments of the call (that describe a buffer) are not in
-// safe patterns:
-
callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
- libc_func_matchers::hasUnsafeSnprintfBuffer())
-.bind(UnsafeSizedByTag),
-// Match a call to a `printf` function, which can be safe if
-// all arguments are null-terminated:
-
callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
- libc_func_matchers::hasUnsafePrintfStringArg(
- expr().bind(UnsafeStringTag);
+  static bool matches(const Stmt *S, ASTContext &Ctx,
+  const UnsafeBufferUsageHandler *Handler,
+  MatchResult &Result) {
+if (ignoreUnsafeLibcCall(Ctx, *S, Handler))
+  return false;
+auto *CE = dyn_cast(S);
+if (!CE || !CE->getDirectCallee())
+  return false;
+const auto *FD = dyn_cast(CE->getDirectCallee());
+if (!FD)
+  return false;
+auto isSingleStringLiteralArg = false;
+if (CE->getNumArgs() == 1) {
+  const auto *const Arg = CE->getArg(0);
+  if (isa(Arg) && !Arg->children().empty()) {

ivanaivanovska wrote:

Done.

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-13 Thread Ivana Ivanovska via cfe-commits


@@ -1139,26 +1276,30 @@ class ArraySubscriptGadget : public WarningGadget {
   const ArraySubscriptExpr *ASE;
 
 public:
-  ArraySubscriptGadget(const MatchFinder::MatchResult &Result)
+  ArraySubscriptGadget(const MatchResult &Result)
   : WarningGadget(Kind::ArraySubscript),
-ASE(Result.Nodes.getNodeAs(ArraySubscrTag)) {}
+ASE(Result.getNodeAs(ArraySubscrTag)) {}
 
   static bool classof(const Gadget *G) {
 return G->getKind() == Kind::ArraySubscript;
   }
 
-  static Matcher matcher() {
-// clang-format off
-  return stmt(arraySubscriptExpr(
-hasBase(ignoringParenImpCasts(
-  anyOf(hasPointerType(), hasArrayType(,
-unless(anyOf(
-  isSafeArraySubscript(),
-  hasIndex(
-  anyOf(integerLiteral(equals(0)), arrayInitIndexExpr())
-  )
-))).bind(ArraySubscrTag));
-// clang-format on
+  static bool matches(const Stmt *S, const ASTContext &Ctx,
+  MatchResult &Result) {
+const auto *ASE = dyn_cast(S);
+if (!ASE)
+  return false;
+const auto *const Base = ASE->getBase()->IgnoreParenImpCasts();
+if (!hasPointerType(*Base) && !hasArrayType(*Base))
+  return false;
+bool IsSafeIndex =
+(isa(ASE->getIdx()) &&
+ cast(ASE->getIdx())->getValue().isZero()) ||
+isa(ASE->getIdx());
+if (isSafeArraySubscript(*ASE, Ctx) || IsSafeIndex)

ivanaivanovska wrote:

Done.

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-13 Thread Ivana Ivanovska via cfe-commits


@@ -1139,26 +1276,30 @@ class ArraySubscriptGadget : public WarningGadget {
   const ArraySubscriptExpr *ASE;
 
 public:
-  ArraySubscriptGadget(const MatchFinder::MatchResult &Result)
+  ArraySubscriptGadget(const MatchResult &Result)
   : WarningGadget(Kind::ArraySubscript),
-ASE(Result.Nodes.getNodeAs(ArraySubscrTag)) {}
+ASE(Result.getNodeAs(ArraySubscrTag)) {}
 
   static bool classof(const Gadget *G) {
 return G->getKind() == Kind::ArraySubscript;
   }
 
-  static Matcher matcher() {
-// clang-format off
-  return stmt(arraySubscriptExpr(
-hasBase(ignoringParenImpCasts(
-  anyOf(hasPointerType(), hasArrayType(,
-unless(anyOf(
-  isSafeArraySubscript(),
-  hasIndex(
-  anyOf(integerLiteral(equals(0)), arrayInitIndexExpr())
-  )
-))).bind(ArraySubscrTag));
-// clang-format on
+  static bool matches(const Stmt *S, const ASTContext &Ctx,
+  MatchResult &Result) {
+const auto *ASE = dyn_cast(S);
+if (!ASE)
+  return false;
+const auto *const Base = ASE->getBase()->IgnoreParenImpCasts();
+if (!hasPointerType(*Base) && !hasArrayType(*Base))
+  return false;
+bool IsSafeIndex =
+(isa(ASE->getIdx()) &&

ivanaivanovska wrote:

Done.

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-13 Thread Ivana Ivanovska via cfe-commits


@@ -186,106 +212,193 @@ class MatchDescendantVisitor : public 
DynamicRecursiveASTVisitor {
 return DynamicRecursiveASTVisitor::TraverseStmt(Node);
   }
 
+  void setASTContext(ASTContext &Context) { ActiveASTContext = &Context; }
+
+  void setHandler(const UnsafeBufferUsageHandler &NewHandler) {
+Handler = &NewHandler;
+  }
+
 private:
   // Sets 'Matched' to true if 'Matcher' matches 'Node'
   //
   // Returns 'true' if traversal should continue after this function
   // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
   template  bool match(const T &Node) {
-internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
-
-if (Matcher->matches(DynTypedNode::create(Node), Finder,
- &RecursiveBuilder)) {
-  ResultBindings.addMatch(RecursiveBuilder);
+if (Matcher->matches(DynTypedNode::create(Node), *ActiveASTContext,
+ *Handler)) {
   Matches = true;
-  if (Bind != internal::ASTMatchFinder::BK_All)
+  if (!FindAll)
 return false; // Abort as soon as a match is found.
 }
 return true;
   }
 
-  const internal::DynTypedMatcher *const Matcher;
-  internal::ASTMatchFinder *const Finder;
-  internal::BoundNodesTreeBuilder *const Builder;
-  internal::BoundNodesTreeBuilder ResultBindings;
-  const internal::ASTMatchFinder::BindKind Bind;
+  FastMatcher *const Matcher;
+  // When true, finds all matches. When false, finds the first match and stops.
+  const bool FindAll;
   bool Matches;
   bool ignoreUnevaluatedContext;
+  ASTContext *ActiveASTContext;
+  const UnsafeBufferUsageHandler *Handler;
 };
 
 // Because we're dealing with raw pointers, let's define what we mean by that.
-static auto hasPointerType() {
-  return hasType(hasCanonicalType(pointerType()));
+static bool hasPointerType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-static auto hasArrayType() { return hasType(hasCanonicalType(arrayType())); }
-
-AST_MATCHER_P(Stmt, forEachDescendantEvaluatedStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
-
-  MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All,
- true);
-  return Visitor.findMatch(DynTypedNode::create(Node));
+static bool hasArrayType(const Expr &E) {
+  return isa(E.getType().getCanonicalType());
 }
 
-AST_MATCHER_P(Stmt, forEachDescendantStmt, internal::Matcher,
-  innerMatcher) {
-  const DynTypedMatcher &DTM = static_cast(innerMatcher);
+static void
+forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx,
+   const UnsafeBufferUsageHandler &Handler,
+   FastMatcher &Matcher) {
+  MatchDescendantVisitor Visitor(Matcher, /*FindAll=*/true,
+ /*ignoreUnevaluatedContext=*/true);
+  Visitor.setASTContext(Ctx);
+  Visitor.setHandler(Handler);

ivanaivanovska wrote:

Changed.

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-13 Thread Ivana Ivanovska via cfe-commits


@@ -1670,30 +1936,41 @@ class ULCArraySubscriptGadget : public FixableGadget {
 };
 
 // Fixable gadget to handle stand alone pointers of the form `UPC(DRE)` in the
-// unspecified pointer context (isInUnspecifiedPointerContext). The gadget 
emits
-// fixit of the form `UPC(DRE.data())`.
+// unspecified pointer context (findStmtsInUnspecifiedPointerContext). The
+// gadget emits fixit of the form `UPC(DRE.data())`.
 class UPCStandalonePointerGadget : public FixableGadget {
 private:
   static constexpr const char *const DeclRefExprTag = "StandalonePointer";
   const DeclRefExpr *Node;
 
 public:
-  UPCStandalonePointerGadget(const MatchFinder::MatchResult &Result)
+  UPCStandalonePointerGadget(const MatchResult &Result)
   : FixableGadget(Kind::UPCStandalonePointer),
-Node(Result.Nodes.getNodeAs(DeclRefExprTag)) {
+Node(Result.getNodeAs(DeclRefExprTag)) {
 assert(Node != nullptr && "Expecting a non-null matching result");
   }
 
   static bool classof(const Gadget *G) {
 return G->getKind() == Kind::UPCStandalonePointer;
   }
 
-  static Matcher matcher() {
-auto ArrayOrPtr = anyOf(hasPointerType(), hasArrayType());
-auto target = expr(ignoringParenImpCasts(
-declRefExpr(allOf(ArrayOrPtr, toSupportedVariable()))
-.bind(DeclRefExprTag)));
-return stmt(isInUnspecifiedPointerContext(target));
+  static bool matches(const Stmt *S,
+  llvm::SmallVectorImpl &Results) {
+bool Found = false;
+findStmtsInUnspecifiedPointerContext(S, [&Found, &Results](const Stmt *S) {

ivanaivanovska wrote:

Removed Found altogether and checking the size of the Results instead.

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-03-13 Thread Ivana Ivanovska via cfe-commits

ivanaivanovska wrote:

Thanks for the review @ziqingluo-90!

https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Optimize -Wunsafe-buffer-usage. (PR #125492)

2025-04-04 Thread Ivana Ivanovska via cfe-commits

https://github.com/ivanaivanovska closed 
https://github.com/llvm/llvm-project/pull/125492
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits