[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 {
+ ASTContext &Ctx;
+ MatcherTy &Matcher;
+ const NamedDecl *RootDecl;
+
+ template <typename T> bool match(const T &Node) {
+ return Matcher.matches(DynTypedNode::create(Node), Ctx, RootDecl);
+ }
+
+public:
+ ContributorFactFinder(ASTContext &Ctx, MatcherTy &Matcher)
+ : Ctx(Ctx), Matcher(Matcher) {
+ ShouldVisitTemplateInstantiations = true;
+ ShouldVisitImplicitCode = false;
+ }
+
+ /// The entry point:
+ void findMatches(const NamedDecl *Contributor) {
+ RootDecl = Contributor;
+ TraverseDecl(const_cast<NamedDecl *>(Contributor));
+ }
+
+ bool TraverseDecl(Decl *Node) override {
+ if (!Node)
+ return true;
+ // To skip callables:
+ if (Node != RootDecl && isa<FunctionDecl, CXXConstructorDecl, BlockDecl,
+ ObjCMethodDecl, RecordDecl>(Node))
+ return true;
+ match(*Node);
+ return DynamicRecursiveASTVisitor::TraverseDecl(Node);
+ }
+
+ bool TraverseStmt(Stmt *Node) override {
+ if (!Node)
+ return true;
+ match(*Node);
+ return DynamicRecursiveASTVisitor::TraverseStmt(Node);
+ }
+
+ bool TraverseLambdaExpr(LambdaExpr *L) override {
+ // TODO: lambda captures of pointer variables (by copy or by reference)
+ // are currently not tracked. Each capture initializes an implicit closure
+ // field from the captured variable, which constitutes a pointer assignment
+ // edge that should be recorded here.
+ return true; // skip lambda as it is a callable
----------------
steakhal wrote:
Comments in [LLVM](https://llvm.org/docs/CodingStandards.html#commenting) are capitalized and punctuated.
https://github.com/llvm/llvm-project/pull/188652
More information about the llvm-branch-commits
mailing list