Skip to content

Commit 526e79f

Browse files
committed
[clang-tidy]detecting conversion directly by make_unique and make_shared in bugprone-optional-value-conversion
Inspired by #110964
1 parent b97c447 commit 526e79f

File tree

3 files changed

+86
-8
lines changed

3 files changed

+86
-8
lines changed

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

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,44 @@
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+
AST_MATCHER_P2(Expr, constructFrom, Matcher<QualType>, TypeMatcher,
31+
Matcher<Expr>, ArgumentMatcher) {
32+
std::array<StringRef, 2> NameList{
33+
"::std::make_unique",
34+
"::std::make_shared",
35+
};
36+
return expr(anyOf(
37+
// construct optional
38+
cxxConstructExpr(argumentCountIs(1U), hasType(TypeMatcher),
39+
hasArgument(0U, ArgumentMatcher)),
40+
// known template methods in std
41+
callExpr(
42+
argumentCountIs(1),
43+
callee(functionDecl(
44+
matchers::matchesAnyListedName(NameList),
45+
hasTemplateArgument(0, refersToType(TypeMatcher)))),
46+
hasArgument(0, ArgumentMatcher))),
47+
unless(
48+
anyOf(hasAncestor(typeLoc()),
49+
hasAncestor(expr(matchers::hasUnevaluatedContext())))))
50+
.matches(Node, Finder, Builder);
51+
}
52+
2953
} // namespace
3054

3155
OptionalValueConversionCheck::OptionalValueConversionCheck(
@@ -67,12 +91,9 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
6791
callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))),
6892
hasArgument(0, ignoringImpCasts(OptionalDereferenceMatcher)));
6993
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())))))
94+
expr(constructFrom(BindOptionalType,
95+
ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
96+
StdMoveCallMatcher))))
7697
.bind("expr"),
7798
this);
7899
}

clang-tools-extra/docs/ReleaseNotes.rst

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

179+
- Improved :doc:`bugprone-optional-value-conversion
180+
<clang-tidy/checks/bugprone/optional-value-conversion>` to support detecting
181+
conversion directly by ``std::make_unique`` and ``std::make_shared``.
182+
179183
- Improved :doc:`bugprone-posix-return
180184
<clang-tidy/checks/bugprone/posix-return>` check to support integer literals
181185
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)