Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[clang-tidy] Add support for bsl::optional#101450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
nicovank merged 7 commits intollvm:mainfromccotter:bsl
Sep 25, 2024
Merged

Conversation

ccotter
Copy link
Contributor

No description provided.

@llvmbotllvmbot added clangClang issues not falling into any other category clang-tools-extra clang-tidy clang:dataflowClang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:analysis labelsAug 1, 2024
@llvmbot
Copy link
Member

llvmbot commentedAug 1, 2024
edited
Loading

@llvm/pr-subscribers-clang-tidy
@llvm/pr-subscribers-clang-tools-extra
@llvm/pr-subscribers-clang-analysis

@llvm/pr-subscribers-clang

Author: Chris Cotter (ccotter)

Changes

Full diff:https://github.com/llvm/llvm-project/pull/101450.diff

5 Files Affected:

  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5)
  • (added) clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bdlb_nullablevalue.h (+38)
  • (added) clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bsl_optional.h (+75)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp (+91)
  • (modified) clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp (+49-13)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rstindex 642ad39cc0c1c..cc999b142561f 100644--- a/clang-tools-extra/docs/ReleaseNotes.rst+++ b/clang-tools-extra/docs/ReleaseNotes.rst@@ -104,6 +104,11 @@ New check aliases Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^+- Improved :doc:`bugprone-unchecked-optional-access+  <clang-tidy/checks/bugprone/unchecked-optional-access>` to support+  `bsl::optional` and `bdlb::NullableValue` from+  <https://github.com/bloomberg/bde>_.+ Removed checks ^^^^^^^^^^^^^^diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bdlb_nullablevalue.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bdlb_nullablevalue.hnew file mode 100644index 0000000000000..53efebba1bb9f--- /dev/null+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bdlb_nullablevalue.h@@ -0,0 +1,38 @@+#ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_BDE_TYPES_NULLABLEVALUE_H_+#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_BDE_TYPES_NULLABLEVALUE_H_++#include "bsl_optional.h"++/// Mock of `bdbl::NullableValue`.+namespace BloombergLP::bdlb {++template <typename T>+class NullableValue : public bsl::optional<T> {+public:+  constexpr NullableValue() noexcept;++  constexpr NullableValue(bsl::nullopt_t) noexcept;++  NullableValue(const NullableValue &) = default;++  NullableValue(NullableValue &&) = default;++  const T &value() const &;+  T &value() &;++  // 'operator bool' is inherited from bsl::optional++  constexpr bool isNull() const noexcept;++  template <typename U>+  constexpr T valueOr(U &&v) const &;++  // 'reset' is inherited from bsl::optional++  template <typename U> NullableValue &operator=(const U &u);+};+++} // namespace BloombergLP::bdlb++#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_BDE_TYPES_NULLABLEVALUE_H_diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bsl_optional.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bsl_optional.hnew file mode 100644index 0000000000000..7e1a129e04a55--- /dev/null+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/bde/types/bsl_optional.h@@ -0,0 +1,75 @@+#ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_BDE_TYPES_OPTIONAL_H_+#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_BDE_TYPES_OPTIONAL_H_++/// Mock of `bsl::optional`.+namespace bsl {++// clang-format off+template <typename T> struct remove_reference      { using type = T; };+template <typename T> struct remove_reference<T&>  { using type = T; };+template <typename T> struct remove_reference<T&&> { using type = T; };+// clang-format on++template <typename T>+using remove_reference_t = typename remove_reference<T>::type;++template <typename T>+constexpr T &&forward(remove_reference_t<T> &t) noexcept;++template <typename T>+constexpr T &&forward(remove_reference_t<T> &&t) noexcept;++template <typename T>+constexpr remove_reference_t<T> &&move(T &&x);++struct nullopt_t {+  constexpr explicit nullopt_t() {}+};++constexpr nullopt_t nullopt;++template <typename T>+class optional {+public:+  constexpr optional() noexcept;++  constexpr optional(nullopt_t) noexcept;++  optional(const optional &) = default;++  optional(optional &&) = default;++  const T &operator*() const &;+  T &operator*() &;+  const T &&operator*() const &&;+  T &&operator*() &&;++  const T *operator->() const;+  T *operator->();++  const T &value() const &;+  T &value() &;+  const T &&value() const &&;+  T &&value() &&;++  constexpr explicit operator bool() const noexcept;+  constexpr bool has_value() const noexcept;++  template <typename U>+  constexpr T value_or(U &&v) const &;+  template <typename U>+  T value_or(U &&v) &&;++  template <typename... Args>+  T &emplace(Args &&...args);++  void reset() noexcept;++  void swap(optional &rhs) noexcept;++  template <typename U> optional &operator=(const U &u);+};++} // namespace bsl++#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_BDE_TYPES_OPTIONAL_H_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.cppindex 13a3ff52f3ebc..3167b85f0e024 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@@ -2,6 +2,8 @@  #include "absl/types/optional.h" #include "folly/types/Optional.h"+#include "bde/types/bsl_optional.h"+#include "bde/types/bdlb_nullablevalue.h"  void unchecked_value_access(const absl::optional<int> &opt) {   opt.value();@@ -50,6 +52,95 @@ void folly_checked_access(const folly::Optional<int> &opt) {   } }+void bsl_optional_unchecked_value_access(const bsl::optional<int> &opt) {+  opt.value();+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  int x = *opt;+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  if (!opt) {+    return;+  }++  opt.value();+  x = *opt;+}++void bsl_optional_checked_access(const bsl::optional<int> &opt) {+  if (opt.has_value()) {+    opt.value();+  }+  if (opt) {+    opt.value();+  }+}++void bsl_optional_value_after_swap(bsl::optional<int> &opt1, bsl::optional<int> &opt2) {+  if (opt1) {+    opt1.swap(opt2);+    opt1.value();+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value+  }+}++void nullable_value_unchecked_value_access(const BloombergLP::bdlb::NullableValue<int> &opt) {+  opt.value();+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  int x = *opt;+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  if (opt.isNull()) {+    opt.value();+  }+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  if (!opt) {+    opt.value();+  }+  // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  if (!opt) {+    return;+  }++  opt.value();+  x = *opt;+}++void nullable_value_optional_checked_access(const BloombergLP::bdlb::NullableValue<int> &opt) {+  if (opt.has_value()) {+    opt.value();+  }+  if (opt) {+    opt.value();+  }+  if (!opt.isNull()) {+    opt.value();+  }+}++void nullable_value_emplaced(BloombergLP::bdlb::NullableValue<int> &opt) {+  opt.value();+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]++  opt.emplace(1);+  opt.value();++  opt.reset();+  opt.value();+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]+}++void nullable_value_after_swap(BloombergLP::bdlb::NullableValue<int> &opt1, BloombergLP::bdlb::NullableValue<int> &opt2) {+  if (opt1) {+    opt1.swap(opt2);+    opt1.value();+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value+  }+}+ template <typename T> void function_template_without_user(const absl::optional<T> &opt) {   opt.value(); // no-warningdiff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cppindex 0707aa662e4cc..9d88754639fa3 100644--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp@@ -38,10 +38,22 @@ namespace clang { namespace dataflow {-static bool isTopLevelNamespaceWithName(const NamespaceDecl &NS,-                                        llvm::StringRef Name) {-  return NS.getDeclName().isIdentifier() && NS.getName() == Name &&-         NS.getParent() != nullptr && NS.getParent()->isTranslationUnit();+template <class... NameTypes>+static bool hasNestedNamespace(const NamespaceDecl &NS, llvm::StringRef Name,+                               NameTypes... Names) {+  if (!(NS.getDeclName().isIdentifier() && NS.getName() == Name &&+        NS.getParent() != nullptr))+    return false;++  if constexpr (sizeof...(NameTypes) > 0) {+    if (NS.getParent()->isTranslationUnit())+      return false;+    if (const auto *NextNS = dyn_cast_or_null<NamespaceDecl>(NS.getParent()))+      return hasNestedNamespace(*NextNS, Names...);+    return false;+  } else {+    return NS.getParent()->isTranslationUnit();+  } }  static bool hasOptionalClassName(const CXXRecordDecl &RD) {@@ -50,15 +62,21 @@ static bool hasOptionalClassName(const CXXRecordDecl &RD) {    if (RD.getName() == "optional") {     if (const auto *N = dyn_cast_or_null<NamespaceDecl>(RD.getDeclContext()))-      return N->isStdNamespace() || isTopLevelNamespaceWithName(*N, "absl");+      return N->isStdNamespace() || hasNestedNamespace(*N, "absl") ||+             hasNestedNamespace(*N, "bsl");     return false;   }    if (RD.getName() == "Optional") {     // Check whether namespace is "::base" or "::folly".     const auto *N = dyn_cast_or_null<NamespaceDecl>(RD.getDeclContext());-    return N != nullptr && (isTopLevelNamespaceWithName(*N, "base") ||-                            isTopLevelNamespaceWithName(*N, "folly"));+    return N != nullptr &&+           (hasNestedNamespace(*N, "base") || hasNestedNamespace(*N, "folly"));+  }++  if (RD.getName() == "NullableValue") {+    const auto *N = dyn_cast_or_null<NamespaceDecl>(RD.getDeclContext());+    return N != nullptr && hasNestedNamespace(*N, "bdlb", "BloombergLP");   }    return false;@@ -195,22 +213,25 @@ auto isOptionalOperatorCallWithName( }  auto isMakeOptionalCall() {-  return callExpr(callee(functionDecl(hasAnyName(-                      "std::make_optional", "base::make_optional",-                      "absl::make_optional", "folly::make_optional"))),-                  hasOptionalType());+  return callExpr(+      callee(functionDecl(hasAnyName(+          "std::make_optional", "base::make_optional", "absl::make_optional",+          "folly::make_optional", "bsl::make_optional"))),+      hasOptionalType()); }  auto nulloptTypeDecl() {   return namedDecl(hasAnyName("std::nullopt_t", "absl::nullopt_t",-                              "base::nullopt_t", "folly::None"));+                              "base::nullopt_t", "folly::None",+                              "bsl::nullopt_t")); }  auto hasNulloptType() { return hasType(nulloptTypeDecl()); }  auto inPlaceClass() {   return recordDecl(hasAnyName("std::in_place_t", "absl::in_place_t",-                               "base::in_place_t", "folly::in_place_t"));+                               "base::in_place_t", "folly::in_place_t",+                               "bsl::in_place_t")); }  auto isOptionalNulloptConstructor() {@@ -415,6 +436,15 @@ void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr,   } }+void transferOptionalIsNullCall(const CXXMemberCallExpr *CallExpr,+                                const MatchFinder::MatchResult &,+                                LatticeTransferState &State) {+  if (auto *HasValueVal = getHasValue(+          State.Env, getImplicitObjectLocation(*CallExpr, State.Env))) {+    State.Env.setValue(*CallExpr, State.Env.makeNot(*HasValueVal));+  }+}+ /// `ModelPred` builds a logical formula relating the predicate in /// `ValueOrPredExpr` to the optional's `has_value` property. void transferValueOrImpl(@@ -784,6 +814,12 @@ auto buildTransferMatchSwitch() {           isOptionalMemberCallWithNameMatcher(hasName("operator bool")),           transferOptionalHasValueCall)+      // NullableValue::isNull+      // Only NullableValue has isNull+      .CaseOfCFGStmt<CXXMemberCallExpr>(+          isOptionalMemberCallWithNameMatcher(hasAnyName("isNull")),+          transferOptionalIsNullCall)+       // optional::emplace       .CaseOfCFGStmt<CXXMemberCallExpr>(           isOptionalMemberCallWithNameMatcher(hasName("emplace")),

Copy link
Member

@PiotrZSLPiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm fine with change, but at the same time this check should be made configurable.
Also please update check documentation before committing.

@ccotter
Copy link
ContributorAuthor

Agreed it should be configurable.

I updated the docs, would you mind merging if you are OK as I don't have perms?

PiotrZSL reacted with thumbs up emoji

@ccotter
Copy link
ContributorAuthor

@ymand could you please re-review?

@ccotter
Copy link
ContributorAuthor

bump@ymand@PiotrZSL?

@ccotterccotter requested a review fromymandAugust 22, 2024 21:07
Copy link

@dayshahdayshah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

huge for bloomberg 🔥

@ccotter
Copy link
ContributorAuthor

bump@ymand@PiotrZSL?

Copy link
Contributor

@nicovanknicovank left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

LGTM. Rebase to fix release notes conflict and I'll merge 👍

ccotterand others added2 commitsSeptember 24, 2024 21:42
…hecked-optional-access/bde/types/bdlb_nullablevalue.hCo-authored-by: Nicolas van Kempen <nvankemp@gmail.com>
@nicovanknicovank merged commit11c423f intollvm:mainSep 25, 2024
9 checks passed
@ccotterccotter deleted the bsl branchFebruary 6, 2025 15:16
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@PiotrZSLPiotrZSLPiotrZSL approved these changes

@nicovanknicovanknicovank approved these changes

@dayshahdayshahdayshah approved these changes

@ymandymandAwaiting requested review from ymand

Assignees
No one assigned
Labels
clang:analysisclang:dataflowClang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.htmlclangClang issues not falling into any other categoryclang-tidyclang-tools-extra
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

6 participants
@ccotter@llvmbot@PiotrZSL@nicovank@ymand@dayshah

[8]ページ先頭

©2009-2025 Movatter.jp