[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>
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
index cf29960..268b51f 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
@@ -120,7 +120,7 @@
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 @@
<< 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
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h
index 5995ad5..f833b80 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.h
@@ -21,8 +21,7 @@
/// 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 @@
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const StringRef ForwardFunction;
};
} // namespace clang::tidy::cppcoreguidelines
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index e50d40b..1e2672b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -212,6 +212,10 @@
<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.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/missing-std-forward.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/missing-std-forward.rst
index 0c311b5..62e38fc 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/missing-std-forward.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/missing-std-forward.rst
@@ -35,6 +35,13 @@
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.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-custom-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-custom-function.cpp
new file mode 100644
index 0000000..7ccac1a
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward-custom-function.cpp
@@ -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)};
+}