Skip to content

Commit 0e4ba47

Browse files
authored
[clang-tidy] support to detect conversion in make_optional for bugprone-optional-value-conversion (llvm#130417)
Add support for std::make_optional. Fixes llvm#119554
1 parent 4d6ca11 commit 0e4ba47

File tree

3 files changed

+39
-3
lines changed

3 files changed

+39
-3
lines changed

clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp

+22-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "../utils/OptionsUtils.h"
1313
#include "clang/AST/ASTContext.h"
1414
#include "clang/ASTMatchers/ASTMatchFinder.h"
15+
#include "clang/ASTMatchers/ASTMatchers.h"
1516
#include <array>
1617

1718
using namespace clang::ast_matchers;
@@ -31,6 +32,7 @@ constexpr std::array<StringRef, 2> MakeSmartPtrList{
3132
"::std::make_unique",
3233
"::std::make_shared",
3334
};
35+
constexpr StringRef MakeOptional = "::std::make_optional";
3436

3537
} // namespace
3638

@@ -83,9 +85,26 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
8385
// known template methods in std
8486
callExpr(
8587
argumentCountIs(1),
86-
callee(functionDecl(
87-
matchers::matchesAnyListedName(MakeSmartPtrList),
88-
hasTemplateArgument(0, refersToType(BindOptionalType)))),
88+
anyOf(
89+
// match std::make_unique std::make_shared
90+
callee(functionDecl(
91+
matchers::matchesAnyListedName(MakeSmartPtrList),
92+
hasTemplateArgument(
93+
0, refersToType(BindOptionalType)))),
94+
// match first std::make_optional by limit argument count
95+
// (1) and template count (1).
96+
// 1. template< class T > constexpr
97+
// std::optional<decay_t<T>> make_optional(T&& value);
98+
// 2. template< class T, class... Args > constexpr
99+
// std::optional<T> make_optional(Args&&... args);
100+
callee(functionDecl(templateArgumentCountIs(1),
101+
hasName(MakeOptional),
102+
returns(BindOptionalType)))),
103+
hasArgument(0, OptionalDerefMatcher)),
104+
callExpr(
105+
106+
argumentCountIs(1),
107+
89108
hasArgument(0, OptionalDerefMatcher))),
90109
unless(anyOf(hasAncestor(typeLoc()),
91110
hasAncestor(expr(matchers::hasUnevaluatedContext())))))

clang-tools-extra/docs/ReleaseNotes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ New check aliases
112112
Changes in existing checks
113113
^^^^^^^^^^^^^^^^^^^^^^^^^^
114114

115+
- Improved :doc:`bugprone-optional-value-conversion
116+
<clang-tidy/checks/bugprone/optional-value-conversion>` check to detect
117+
conversion in argument of ``std::make_optional``.
118+
115119
- Improved :doc:`bugprone-string-constructor
116120
<clang-tidy/checks/bugprone/string-constructor>` check to find suspicious
117121
calls of ``std::string`` constructor with char pointer, start position and

clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,19 @@ class unique_ptr {};
2727
template <typename type>
2828
class shared_ptr {};
2929

30+
template <typename T>
31+
class initializer_list {};
32+
3033
template <class T, class... Args> unique_ptr<T> make_unique(Args &&...args);
3134
template <class T, class... Args> shared_ptr<T> make_shared(Args &&...args);
3235

36+
template <class T>
37+
constexpr std::optional<__decay(T)> make_optional(T &&value);
38+
template <class T, class... Args>
39+
constexpr std::optional<T> make_optional(Args &&...args);
40+
template <class T, class U, class... Args>
41+
constexpr std::optional<T> make_optional(std::initializer_list<U> il, Args &&...args);
42+
3343
} // namespace std
3444

3545
struct A {
@@ -45,9 +55,12 @@ void invalid() {
4555
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
4656
std::make_shared<std::optional<int>>(opt.value());
4757
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
58+
std::make_optional(opt.value());
59+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
4860
}
4961

5062
void valid() {
5163
std::make_unique<A>(opt.value());
5264
std::make_shared<A>(opt.value());
65+
std::make_optional<int>(opt.value());
5366
}

0 commit comments

Comments
 (0)