[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>
This commit is contained in:
committed by
GitHub
parent
ba84d0c8d7
commit
6a57af8d03
@@ -120,7 +120,7 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {
|
||||
equalsBoundNode("param"), equalsBoundNode("var")))))),
|
||||
CapturedInLambda)),
|
||||
callee(unresolvedLookupExpr(hasAnyDeclaration(
|
||||
namedDecl(hasUnderlyingDecl(hasName("::std::forward")))))),
|
||||
namedDecl(hasUnderlyingDecl(hasName(ForwardFunction)))))),
|
||||
|
||||
unless(anyOf(hasAncestor(typeLoc()),
|
||||
hasAncestor(expr(hasUnevaluatedContext())))));
|
||||
@@ -149,4 +149,13 @@ void MissingStdForwardCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
<< Param;
|
||||
}
|
||||
|
||||
MissingStdForwardCheck::MissingStdForwardCheck(StringRef Name,
|
||||
ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
ForwardFunction(Options.get("ForwardFunction", "::std::forward")) {}
|
||||
|
||||
void MissingStdForwardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
||||
Options.store(Opts, "ForwardFunction", ForwardFunction);
|
||||
}
|
||||
|
||||
} // namespace clang::tidy::cppcoreguidelines
|
||||
|
||||
@@ -21,8 +21,7 @@ namespace clang::tidy::cppcoreguidelines {
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/missing-std-forward.html
|
||||
class MissingStdForwardCheck : public ClangTidyCheck {
|
||||
public:
|
||||
MissingStdForwardCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
MissingStdForwardCheck(StringRef Name, ClangTidyContext *Context);
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
|
||||
@@ -31,6 +30,10 @@ public:
|
||||
std::optional<TraversalKind> getCheckTraversalKind() const override {
|
||||
return TK_IgnoreUnlessSpelledInSource;
|
||||
}
|
||||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
|
||||
|
||||
private:
|
||||
const StringRef ForwardFunction;
|
||||
};
|
||||
|
||||
} // namespace clang::tidy::cppcoreguidelines
|
||||
|
||||
@@ -212,6 +212,10 @@ Changes in existing checks
|
||||
<clang-tidy/checks/cppcoreguidelines/avoid-goto>` check by adding the option
|
||||
`IgnoreMacros` to ignore ``goto`` labels defined in macros.
|
||||
|
||||
- Improved :doc:`cppcoreguidelines-missing-std-forward
|
||||
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by adding a
|
||||
flag to specify the function used for forwarding instead of ``std::forward``.
|
||||
|
||||
- Improved :doc:`cppcoreguidelines-special-member-functions
|
||||
<clang-tidy/checks/cppcoreguidelines/special-member-functions>` check by
|
||||
adding the option `IgnoreMacros` to ignore classes defined in macros.
|
||||
|
||||
@@ -35,6 +35,13 @@ Example:
|
||||
f(1, 2); // Incorrect - may not invoke the desired qualified function operator
|
||||
}
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. option:: ForwardFunction
|
||||
|
||||
Specify the function used for forwarding. Default is `::std::forward`.
|
||||
|
||||
This check implements `F.19
|
||||
<http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-forward>`_
|
||||
from the C++ Core Guidelines.
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// RUN: %check_clang_tidy -std=c++14 %s cppcoreguidelines-missing-std-forward %t -- \
|
||||
// RUN: -config="{CheckOptions: {cppcoreguidelines-missing-std-forward.ForwardFunction: custom_forward}}" -- -fno-delayed-template-parsing
|
||||
|
||||
// NOLINTBEGIN
|
||||
namespace std {
|
||||
|
||||
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; };
|
||||
|
||||
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);
|
||||
|
||||
} // namespace std
|
||||
// NOLINTEND
|
||||
|
||||
template<class T>
|
||||
constexpr decltype(auto) custom_forward(std::remove_reference_t<T>& tmp) noexcept
|
||||
{
|
||||
return static_cast<T&&>(tmp);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr decltype(auto) custom_forward(std::remove_reference_t<T>&& tmp) noexcept
|
||||
{
|
||||
return static_cast<T&&>(tmp);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void forward_with_std(T&& t) {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference parameter 't' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
|
||||
|
||||
T other{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void move_with_custom(T&& t) {
|
||||
T other{custom_forward<T>(t)};
|
||||
}
|
||||
Reference in New Issue
Block a user