[clang] [clang-tools-extra] [clang-tidy] fix false positive in bugprone-unchecked-optional-access for nested loops (PR #177858)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 25 06:15:20 PST 2026
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/177858
>From d2ec6c53b7c534258dd08fdbe9fd183c09cf0de4 Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Sun, 25 Jan 2026 22:09:53 +0800
Subject: [PATCH] [clang-tidy] fix false positive in
bugprone-unchecked-optional-access for nested loops
---
clang-tools-extra/docs/ReleaseNotes.rst | 5 +++
.../bugprone/unchecked-optional-access.cpp | 35 +++++++++++++++++++
.../Models/UncheckedOptionalAccessModel.cpp | 8 +++--
3 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 5af634c77f54d..0b2bde80edff2 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -109,6 +109,11 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Improved :doc:`bugprone-unchecked-optional-access
+ <clang-tidy/checks/bugprone/unchecked-optional-access>` check to avoid false
+ positives in nested loops by excluding generic const accessors from
+ unnecessary dataflow analysis.
+
- Improved :doc:`bugprone-unsafe-functions
<clang-tidy/checks/bugprone/unsafe-functions>` check by adding the function
``std::get_temporary_buffer`` to the default list of unsafe functions. (This
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
index 984156c028c00..14672f5ab5546 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
@@ -370,3 +370,38 @@ void foo() {
if (!vec.empty())
vec[0].x = 0;
}
+
+namespace std {
+template <typename T>
+struct vector_iterator {
+ T& operator*();
+ vector_iterator& operator++();
+ bool operator!=(const vector_iterator&);
+};
+
+template <typename T>
+struct vector_with_iter {
+ vector_iterator<T> begin();
+ vector_iterator<T> end();
+};
+
+} // namespace std
+
+void nested_loops() {
+ std::vector_with_iter<absl::optional<int>> optionals;
+ for (const auto &opt : optionals) {
+ if (opt.has_value()) {
+ for (int i = 0; i < 10; ++i) {
+ opt.value(); // no-warning
+ }
+ }
+ }
+
+ for (const auto &opt : optionals) {
+ if (opt.has_value()) {
+ for (;;) {
+ opt.value(); // no-warning
+ }
+ }
+ }
+}
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 04a2a557debb2..dcc88f8a7f838 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -338,13 +338,15 @@ auto isValueOrNotEqX() {
}
auto isZeroParamConstMemberCall() {
- return cxxMemberCallExpr(
- callee(cxxMethodDecl(parameterCountIs(0), isConst())));
+ return cxxMemberCallExpr(callee(cxxMethodDecl(
+ parameterCountIs(0), isConst(),
+ unless(hasAnyName("value", "has_value", "hasValue", "operator bool")))));
}
auto isZeroParamConstMemberOperatorCall() {
return cxxOperatorCallExpr(
- callee(cxxMethodDecl(parameterCountIs(0), isConst())));
+ callee(cxxMethodDecl(parameterCountIs(0), isConst(),
+ unless(hasAnyName("operator*", "operator->")))));
}
auto isNonConstMemberCall() {
More information about the cfe-commits
mailing list