[llvm-branch-commits] [clang] [SSAF][UnsafeBufferUsage] Implement AST visitor that respects the contribution model (PR #188652)

Balázs Benics via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Apr 7 13:53:28 PDT 2026


================
@@ -0,0 +1,148 @@
+//===-- SSAFAnalysesCommon.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  Common code in SSAF analyses implementations
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_SSAFANALYSESCOMMON_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_SSAFANALYSESCOMMON_H
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DynamicRecursiveASTVisitor.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/JSON.h"
+
+using namespace clang;
+
+template <typename NodeTy, typename... Ts>
+static inline llvm::Error makeErrAtNode(ASTContext &Ctx, const NodeTy &N,
+                                        StringRef Fmt, const Ts &...Args) {
+  std::string LocStr = N.getBeginLoc().printToString(Ctx.getSourceManager());
+  llvm::SmallVector<char> FmtData;
+
+  (Fmt + " at %s").toStringRef(FmtData);
+  return llvm::createStringError(FmtData.data(), Args..., LocStr.c_str());
+}
+
+static inline llvm::Error makeEntityNameErr(ASTContext &Ctx,
+                                            const NamedDecl &D) {
+  return makeErrAtNode(Ctx, D, "failed to create entity name for %s",
+                       D.getNameAsString().data());
+}
+
+static inline llvm::Error makeAddEntitySummaryErr(ASTContext &Ctx,
+                                                  const NamedDecl *D) {
+  std::string LocStr = D->getBeginLoc().printToString(Ctx.getSourceManager());
+
+  return llvm::createStringError("failed to add entity summary for %s at %s",
+                                 D->getNameAsString().data(), LocStr.c_str());
+}
+
+template <typename... Ts>
+static inline llvm::Error makeSawButExpectedError(const llvm::json::Value &Saw,
+                                                  llvm::StringRef Expected,
+                                                  const Ts &...ExpectedArgs) {
+  std::string Fmt = ("saw %s but expected " + Expected).str();
+  std::string SawStr = llvm::formatv("{0:2}", Saw).str();
+
+  return llvm::createStringError(Fmt.c_str(), SawStr.c_str(), ExpectedArgs...);
+}
+
+template <typename DeclOrExpr>
+static inline bool hasPtrOrArrType(const DeclOrExpr &E) {
+  return llvm::isa<PointerType>(E.getType().getCanonicalType()) ||
+         llvm::isa<ArrayType>(E.getType().getCanonicalType());
+}
+
+namespace clang::ssaf {
+/// Traverses the AST and finds contributors:
+class ContributorFinder : public DynamicRecursiveASTVisitor {
+public:
+  std::vector<const NamedDecl *> Contributors;
+
+  bool VisitFunctionDecl(FunctionDecl *D) override {
+    Contributors.push_back(D);
+    return true;
+  }
+
+  bool VisitRecordDecl(RecordDecl *D) override {
+    Contributors.push_back(D);
+    return true;
+  }
+
+  bool VisitVarDecl(VarDecl *D) override {
+    DeclContext *DC = D->getDeclContext();
+
+    if (DC->isFileContext() || DC->isNamespace())
+      Contributors.push_back(D);
+    return true;
+  }
+};
+
+/// An AST visitor that skips the root node's strict-descendants that are
+/// callable Decls and record Decls, because those are separate contributors.
+///
+/// The visitor calls
+/// `MatcherTy::matchFact(DynTypedNode &, ASTContext &, const NamedDecl
+/// *Contributor)` on each visited Decl or Stmt node to collect facts in the
+/// `Contributor`.
+template <typename MatcherTy>
+class ContributorFactFinder : public DynamicRecursiveASTVisitor {
----------------
steakhal wrote:

I'm concerned about this class being template, especially because I think we could get away using the same stuff that is used in clang-query.
`DynTypedMatcher` should be able to represent AST matchers in a type-erased way. TBH, the overhead of that type-erasure should be small enough compared to the matching traversal that it should be not noticeable.

After this, you could move all of these to a CPP file.

https://github.com/llvm/llvm-project/pull/188652


More information about the llvm-branch-commits mailing list