[clang] 4720d95 - Fix registered matcher for bugprone-unchecked-optional-access (recent changes to libcxx) (#191681)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 14 23:36:26 PDT 2026
Author: Jan Voung
Date: 2026-04-15T06:36:21Z
New Revision: 4720d95026c7ef71e9743135d58fd6cdb06988e7
URL: https://github.com/llvm/llvm-project/commit/4720d95026c7ef71e9743135d58fd6cdb06988e7
DIFF: https://github.com/llvm/llvm-project/commit/4720d95026c7ef71e9743135d58fd6cdb06988e7.diff
LOG: Fix registered matcher for bugprone-unchecked-optional-access (recent changes to libcxx) (#191681)
Further fix for #187788. Previous attempt in PR #188044 only updated the
model and model tests, but forgot to update the registered matcher.
Added:
Modified:
clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
index 79d6e4974c316..cf7829984fab9 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
@@ -27,8 +27,9 @@ static constexpr StringRef FuncID = "fun";
void UncheckedOptionalAccessCheck::registerMatchers(MatchFinder *Finder) {
using namespace ast_matchers;
- auto HasOptionalCallDescendant = hasDescendant(callExpr(callee(cxxMethodDecl(
- ofClass(UncheckedOptionalAccessModel::optionalClassDecl())))));
+ auto HasOptionalCallDescendant = hasDescendant(callExpr(
+ anyOf(UncheckedOptionalAccessModel::memberCallToOptionalClass(),
+ UncheckedOptionalAccessModel::operatorCallToOptionalClass())));
Finder->addMatcher(
decl(anyOf(functionDecl(
// FIXME: Remove the filter below when lambdas are
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
index d331585a4c21c..c508b2abe6e47 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
@@ -1,6 +1,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_STD_TYPES_OPTIONAL_H_
#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_STD_TYPES_OPTIONAL_H_
+/// Mock of `std::optional`.
namespace std {
struct nullopt_t {
@@ -9,16 +10,13 @@ struct nullopt_t {
constexpr nullopt_t nullopt;
-template <typename T>
-class optional {
-public:
- constexpr optional() noexcept;
-
- constexpr optional(nullopt_t) noexcept;
-
- optional(const optional &) = default;
+template <class T> struct __optional_destruct_base {
+ constexpr void reset() noexcept;
+};
- optional(optional &&) = default;
+template <class T>
+struct __optional_storage_base : __optional_destruct_base<T> {
+ constexpr bool has_value() const noexcept;
const T &operator*() const &;
T &operator*() &;
@@ -32,9 +30,28 @@ class optional {
T &value() &;
const T &&value() const &&;
T &&value() &&;
+};
+
+// Note: the inheritance may or may not be private:
+// https://github.com/llvm/llvm-project/issues/187788
+template <typename T> class optional : public __optional_storage_base<T> {
+ using base = __optional_storage_base<T>;
+
+public:
+ constexpr optional() noexcept;
+
+ constexpr optional(nullopt_t) noexcept;
+
+ optional(const optional &) = default;
+
+ optional(optional &&) = default;
+
+ using base::operator*;
+ using base::operator->;
+ using base::value;
constexpr explicit operator bool() const noexcept;
- constexpr bool has_value() const noexcept;
+ using base::has_value;
template <typename U>
constexpr T value_or(U &&v) const &;
@@ -44,7 +61,7 @@ class optional {
template <typename... Args>
T &emplace(Args &&...args);
- void reset() noexcept;
+ using base::reset;
void swap(optional &rhs) noexcept;
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 214072de772e2..337474bdf7535 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
@@ -1,16 +1,27 @@
// RUN: %check_clang_tidy %s bugprone-unchecked-optional-access %t -- -- -I %S/Inputs/unchecked-optional-access
#include "absl/types/optional.h"
-#include "folly/types/Optional.h"
-#include "bde/types/bsl_optional.h"
#include "bde/types/bdlb_nullablevalue.h"
+#include "bde/types/bsl_optional.h"
+#include "folly/types/Optional.h"
+#include "std/types/optional.h"
-void unchecked_value_access(const absl::optional<int> &opt) {
+void unchecked_value_access(std::optional<int> opt) {
opt.value();
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
}
-void unchecked_deref_operator_access(const absl::optional<int> &opt) {
+void absl_unchecked_value_access(const absl::optional<int> &opt) {
+ opt.value();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
+}
+
+void unchecked_deref_operator_access(std::optional<int> opt) {
+ *opt;
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional value
+}
+
+void absl_unchecked_deref_operator_access(const absl::optional<int> &opt) {
*opt;
// CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional value
}
@@ -19,7 +30,12 @@ struct Foo {
void foo() const {}
};
-void unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
+void unchecked_arrow_operator_access(std::optional<Foo> opt) {
+ opt->foo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
+}
+
+void absl_unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
opt->foo();
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
}
@@ -40,7 +56,13 @@ void folly_value_after_swap(folly::Optional<int> opt1, folly::Optional<int> opt2
}
}
-void checked_access(const absl::optional<int> &opt) {
+void checked_access(std::optional<int> opt) {
+ if (opt.has_value()) {
+ opt.value();
+ }
+}
+
+void absl_checked_access(const absl::optional<int> &opt) {
if (opt.has_value()) {
opt.value();
}
diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
index c547d6ce2e387..e7f1f407d9912 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
@@ -62,8 +62,9 @@ class UncheckedOptionalAccessModel
public:
UncheckedOptionalAccessModel(ASTContext &Ctx, dataflow::Environment &Env);
- /// Returns a matcher for the optional classes covered by this model.
- static ast_matchers::DeclarationMatcher optionalClassDecl();
+ /// Returns a matcher for calls to optional classes diagnosed by this model.
+ static ast_matchers::StatementMatcher memberCallToOptionalClass();
+ static ast_matchers::StatementMatcher operatorCallToOptionalClass();
static UncheckedOptionalAccessLattice initialElement() { return {}; }
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 182db36be3513..568564fb361f4 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -1278,9 +1278,14 @@ auto buildDiagnoseMatchSwitch(
} // namespace
-ast_matchers::DeclarationMatcher
-UncheckedOptionalAccessModel::optionalClassDecl() {
- return cxxRecordDecl(optionalClass());
+ast_matchers::StatementMatcher
+UncheckedOptionalAccessModel::memberCallToOptionalClass() {
+ return cxxMemberCallExpr(hasOptionalReceiverType());
+}
+
+ast_matchers::StatementMatcher
+UncheckedOptionalAccessModel::operatorCallToOptionalClass() {
+ return cxxOperatorCallExpr(hasOptionalOperatorObjectType());
}
UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx,
More information about the cfe-commits
mailing list