[clang] [clang] Trigger checkLifetimeEnd callback from CFGLifetimeEnds element (PR #201123)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 4 00:56:20 PDT 2026
================
@@ -0,0 +1,106 @@
+//===- unittests/StaticAnalyzer/CheckLifetimeEndTest.cpp ------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CheckerRegistration.h"
+#include "Reusables.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
+#include "llvm/Config/llvm-config.h"
+#include "gtest/gtest.h"
+
+namespace {
+using namespace clang;
+using namespace ento;
+
+class LifetimeEndReporter : public Checker<check::LifetimeEnd> {
+ const BugType LifetimeEndNode{this, "LifetimeEndReporter"};
+
+ bool report(CheckerContext &C, Twine Description) const {
+ ExplodedNode *Node = C.generateNonFatalErrorNode(C.getState());
+ if (!Node)
+ return false;
+
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ LifetimeEndNode, Description.str(), Node);
+ C.emitReport(std::move(Report));
+ return true;
+ }
+
+public:
+ void checkLifetimeEnd(const VarDecl *D, CheckerContext &C) const {
+ auto II = D->getIdentifier();
+ ASSERT_TRUE(II != nullptr);
+ report(C, II->getName() + " LIFETIME END");
+ }
+};
+
+void addLifetimeEndReporter(AnalysisASTConsumer &AnalysisConsumer,
+ AnalyzerOptions &AnOpts) {
+ AnOpts.CheckersAndPackages = {
+ {"test.LifetimeEndReporter", true},
+ };
+ AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
+ Registry.addChecker<LifetimeEndReporter>(
+ "test.LifetimeEndReporter", "EmptyDescription", "EmptyDocsUri");
+ });
+}
+
+const std::vector<std::string> DisableLifetimeArgs{
+ "-Xclang", "-analyzer-config", "-Xclang", "cfg-lifetime=false"};
+const std::vector<std::string> EnableLifetimeArgs{
+ "-Xclang", "-analyzer-config", "-Xclang", "cfg-lifetime=true"};
+
+TEST(CheckLifetimeEnd, CFGLifetimeEnabled) {
+ constexpr auto Code = R"(
+void foo() {
+ int i = 0;
+}
+ )";
+
+ std::string Diags;
+ EXPECT_TRUE(runCheckerOnCodeWithArgs<addLifetimeEndReporter>(
+ Code, EnableLifetimeArgs, Diags, /*OnlyEmitWarnings=*/true));
+ EXPECT_EQ(Diags, "test.LifetimeEndReporter: i LIFETIME END\n");
+}
----------------
steakhal wrote:
You tried hard not checking the CFG dumps in LIT.
While this test demonstrates that the callback gets called, and that replies with some plausible parameterization, it doesn't demonstrate that the CFG element is at the right place relative to the other CFGElements.
I think we should also test:
- multiple variables on stack
- local static: does not call lifetime ends
- local variables within nested blocks (like a local variable within the loop, or the loop induction variable lifetime)
- how it works with lifetime extension
https://github.com/llvm/llvm-project/pull/201123
More information about the cfe-commits
mailing list