Skip to content

Commit ba373a2

Browse files
authored
[clang-tidy]detecting conversion directly by make_unique and make_shared in bugprone-optional-value-conversion (#119371)
Inspired by #110964
1 parent 4b825c7 commit ba373a2

File tree

3 files changed

+85
-8
lines changed

3 files changed

+85
-8
lines changed

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

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,43 @@
1212
#include "../utils/OptionsUtils.h"
1313
#include "clang/AST/ASTContext.h"
1414
#include "clang/ASTMatchers/ASTMatchFinder.h"
15+
#include <array>
1516

1617
using namespace clang::ast_matchers;
18+
using clang::ast_matchers::internal::Matcher;
1719

1820
namespace clang::tidy::bugprone {
1921

2022
namespace {
2123

22-
AST_MATCHER_P(QualType, hasCleanType, ast_matchers::internal::Matcher<QualType>,
23-
InnerMatcher) {
24+
AST_MATCHER_P(QualType, hasCleanType, Matcher<QualType>, InnerMatcher) {
2425
return InnerMatcher.matches(
2526
Node.getNonReferenceType().getUnqualifiedType().getCanonicalType(),
2627
Finder, Builder);
2728
}
2829

30+
constexpr std::array<StringRef, 2> NameList{
31+
"::std::make_unique",
32+
"::std::make_shared",
33+
};
34+
35+
Matcher<Expr> constructFrom(Matcher<QualType> TypeMatcher,
36+
Matcher<Expr> ArgumentMatcher) {
37+
return expr(
38+
anyOf(
39+
// construct optional
40+
cxxConstructExpr(argumentCountIs(1U), hasType(TypeMatcher),
41+
hasArgument(0U, ArgumentMatcher)),
42+
// known template methods in std
43+
callExpr(argumentCountIs(1),
44+
callee(functionDecl(
45+
matchers::matchesAnyListedName(NameList),
46+
hasTemplateArgument(0, refersToType(TypeMatcher)))),
47+
hasArgument(0, ArgumentMatcher))),
48+
unless(anyOf(hasAncestor(typeLoc()),
49+
hasAncestor(expr(matchers::hasUnevaluatedContext())))));
50+
}
51+
2952
} // namespace
3053

3154
OptionalValueConversionCheck::OptionalValueConversionCheck(
@@ -67,12 +90,9 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
6790
callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))),
6891
hasArgument(0, ignoringImpCasts(OptionalDereferenceMatcher)));
6992
Finder->addMatcher(
70-
cxxConstructExpr(
71-
argumentCountIs(1U), hasType(BindOptionalType),
72-
hasArgument(0U, ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
73-
StdMoveCallMatcher))),
74-
unless(anyOf(hasAncestor(typeLoc()),
75-
hasAncestor(expr(matchers::hasUnevaluatedContext())))))
93+
expr(constructFrom(BindOptionalType,
94+
ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
95+
StdMoveCallMatcher))))
7696
.bind("expr"),
7797
this);
7898
}

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ Changes in existing checks
182182
<clang-tidy/checks/bugprone/forwarding-reference-overload>` check by fixing
183183
a crash when determining if an ``enable_if[_t]`` was found.
184184

185+
- Improved :doc:`bugprone-optional-value-conversion
186+
<clang-tidy/checks/bugprone/optional-value-conversion>` to support detecting
187+
conversion directly by ``std::make_unique`` and ``std::make_shared``.
188+
185189
- Improved :doc:`bugprone-posix-return
186190
<clang-tidy/checks/bugprone/posix-return>` check to support integer literals
187191
as LHS and posix call as RHS of comparison.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-optional-value-conversion %t
2+
3+
namespace std {
4+
template <typename T> struct optional {
5+
constexpr optional() noexcept;
6+
constexpr optional(T &&) noexcept;
7+
constexpr optional(const T &) noexcept;
8+
template <typename U> constexpr optional(U &&) noexcept;
9+
const T &operator*() const;
10+
T *operator->();
11+
const T *operator->() const;
12+
T &operator*();
13+
const T &value() const;
14+
T &value();
15+
const T &get() const;
16+
T &get();
17+
T value_or(T) const;
18+
};
19+
20+
template <class T> T &&move(T &x) { return static_cast<T &&>(x); }
21+
22+
template <typename T> class default_delete {};
23+
24+
template <typename type, typename Deleter = std::default_delete<type>>
25+
class unique_ptr {};
26+
27+
template <typename type>
28+
class shared_ptr {};
29+
30+
template <class T, class... Args> unique_ptr<T> make_unique(Args &&...args);
31+
template <class T, class... Args> shared_ptr<T> make_shared(Args &&...args);
32+
33+
} // namespace std
34+
35+
struct A {
36+
explicit A (int);
37+
};
38+
std::optional<int> opt;
39+
40+
void invalid() {
41+
std::make_unique<std::optional<int>>(opt.value());
42+
// 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]
43+
using A = std::optional<int>;
44+
std::make_unique<A>(opt.value());
45+
// 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]
46+
std::make_shared<std::optional<int>>(opt.value());
47+
// 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]
48+
}
49+
50+
void valid() {
51+
std::make_unique<A>(opt.value());
52+
std::make_shared<A>(opt.value());
53+
}

0 commit comments

Comments
 (0)