Skip to content

Commit 6a57af8

Browse files
[clang-tidy] Add flag to specify an alternative to std::forward (#138755)
Since std::forward is nothing more than a cast, part of STL and not the language itself, it's easy to provide a custom implementation if one wishes not to include the entirety of <utility>. Added flag (ForwardFunction) provides a way to continue using this essential check even with the custom implementation of forwarding. --------- Co-authored-by: EugeneZelenko <eugene.zelenko@gmail.com>
1 parent ba84d0c commit 6a57af8

File tree

5 files changed

+68
-3
lines changed

5 files changed

+68
-3
lines changed

clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {
120120
equalsBoundNode("param"), equalsBoundNode("var")))))),
121121
CapturedInLambda)),
122122
callee(unresolvedLookupExpr(hasAnyDeclaration(
123-
namedDecl(hasUnderlyingDecl(hasName("::std::forward")))))),
123+
namedDecl(hasUnderlyingDecl(hasName(ForwardFunction)))))),
124124

125125
unless(anyOf(hasAncestor(typeLoc()),
126126
hasAncestor(expr(hasUnevaluatedContext())))));
@@ -149,4 +149,13 @@ void MissingStdForwardCheck::check(const MatchFinder::MatchResult &Result) {
149149
<< Param;
150150
}
151151

152+
MissingStdForwardCheck::MissingStdForwardCheck(StringRef Name,
153+
ClangTidyContext *Context)
154+
: ClangTidyCheck(Name, Context),
155+
ForwardFunction(Options.get("ForwardFunction", "::std::forward")) {}
156+
157+
void MissingStdForwardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
158+
Options.store(Opts, "ForwardFunction", ForwardFunction);
159+
}
160+
152161
} // namespace clang::tidy::cppcoreguidelines

clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ namespace clang::tidy::cppcoreguidelines {
2121
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/missing-std-forward.html
2222
class MissingStdForwardCheck : public ClangTidyCheck {
2323
public:
24-
MissingStdForwardCheck(StringRef Name, ClangTidyContext *Context)
25-
: ClangTidyCheck(Name, Context) {}
24+
MissingStdForwardCheck(StringRef Name, ClangTidyContext *Context);
2625
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
2726
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
2827
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
@@ -31,6 +30,10 @@ class MissingStdForwardCheck : public ClangTidyCheck {
3130
std::optional<TraversalKind> getCheckTraversalKind() const override {
3231
return TK_IgnoreUnlessSpelledInSource;
3332
}
33+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
34+
35+
private:
36+
const StringRef ForwardFunction;
3437
};
3538

3639
} // namespace clang::tidy::cppcoreguidelines

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ Changes in existing checks
212212
<clang-tidy/checks/cppcoreguidelines/avoid-goto>` check by adding the option
213213
`IgnoreMacros` to ignore ``goto`` labels defined in macros.
214214

215+
- Improved :doc:`cppcoreguidelines-missing-std-forward
216+
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by adding a
217+
flag to specify the function used for forwarding instead of ``std::forward``.
218+
215219
- Improved :doc:`cppcoreguidelines-special-member-functions
216220
<clang-tidy/checks/cppcoreguidelines/special-member-functions>` check by
217221
adding the option `IgnoreMacros` to ignore classes defined in macros.

clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/missing-std-forward.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ Example:
3535
f(1, 2); // Incorrect - may not invoke the desired qualified function operator
3636
}
3737

38+
Options
39+
-------
40+
41+
.. option:: ForwardFunction
42+
43+
Specify the function used for forwarding. Default is `::std::forward`.
44+
3845
This check implements `F.19
3946
<http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-forward>`_
4047
from the C++ Core Guidelines.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %check_clang_tidy -std=c++14 %s cppcoreguidelines-missing-std-forward %t -- \
2+
// RUN: -config="{CheckOptions: {cppcoreguidelines-missing-std-forward.ForwardFunction: custom_forward}}" -- -fno-delayed-template-parsing
3+
4+
// NOLINTBEGIN
5+
namespace std {
6+
7+
template <typename T> struct remove_reference { using type = T; };
8+
template <typename T> struct remove_reference<T&> { using type = T; };
9+
template <typename T> struct remove_reference<T&&> { using type = T; };
10+
11+
template <typename T> using remove_reference_t = typename remove_reference<T>::type;
12+
13+
template <typename T> constexpr T &&forward(remove_reference_t<T> &t) noexcept;
14+
template <typename T> constexpr T &&forward(remove_reference_t<T> &&t) noexcept;
15+
template <typename T> constexpr remove_reference_t<T> &&move(T &&x);
16+
17+
} // namespace std
18+
// NOLINTEND
19+
20+
template<class T>
21+
constexpr decltype(auto) custom_forward(std::remove_reference_t<T>& tmp) noexcept
22+
{
23+
return static_cast<T&&>(tmp);
24+
}
25+
26+
template<class T>
27+
constexpr decltype(auto) custom_forward(std::remove_reference_t<T>&& tmp) noexcept
28+
{
29+
return static_cast<T&&>(tmp);
30+
}
31+
32+
template<class T>
33+
void forward_with_std(T&& t) {
34+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference parameter 't' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
35+
36+
T other{std::forward<T>(t)};
37+
}
38+
39+
template<class T>
40+
void move_with_custom(T&& t) {
41+
T other{custom_forward<T>(t)};
42+
}

0 commit comments

Comments
 (0)