[clang-tidy] Ignore standard tag dispatch types in readability-named-parameter (#208730)
Parameters whose type is a standard tag type (e.g. std::in_place_t, std::nothrow_t, iterator tags, lock tags) are used purely for overload resolution and don't need a name. This patch skips them. Added an IgnoredTypes option so users can customize the list. Default covers 24 standard tag types. Fixes #208448. AI Usage: This commit is AI-assisted, reviewed and verified by me.
This commit is contained in:
parent
8eca60b49a
commit
d0ec2ec1f2
6 changed files with 171 additions and 1 deletions
|
|
@ -7,6 +7,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "NamedParameterCheck.h"
|
||||
#include "../utils/OptionsUtils.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
|
|
@ -15,15 +16,47 @@ using namespace clang::ast_matchers;
|
|||
|
||||
namespace clang::tidy::readability {
|
||||
|
||||
// Types whose parameters do not need a name (tag dispatch types, category
|
||||
// tags, etc.).
|
||||
static constexpr StringRef DefaultIgnoredTypes =
|
||||
"std::adopt_lock_t;"
|
||||
"std::allocator_arg_t;"
|
||||
"std::bidirectional_iterator_tag;"
|
||||
"std::contiguous_iterator_tag;"
|
||||
"std::default_sentinel_t;"
|
||||
"std::defer_lock_t;"
|
||||
"std::destroying_delete_t;"
|
||||
"std::forward_iterator_tag;"
|
||||
"std::from_range_t;"
|
||||
"std::in_place_index_t;"
|
||||
"std::in_place_t;"
|
||||
"std::in_place_type_t;"
|
||||
"std::input_iterator_tag;"
|
||||
"std::nothrow_t;"
|
||||
"std::nostopstate_t;"
|
||||
"std::nullopt_t;"
|
||||
"std::output_iterator_tag;"
|
||||
"std::piecewise_construct_t;"
|
||||
"std::random_access_iterator_tag;"
|
||||
"std::sorted_equivalent_t;"
|
||||
"std::sorted_unique_t;"
|
||||
"std::try_to_lock_t;"
|
||||
"std::unexpect_t;"
|
||||
"std::unreachable_sentinel_t";
|
||||
|
||||
NamedParameterCheck::NamedParameterCheck(StringRef Name,
|
||||
ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
InsertPlainNamesInForwardDecls(
|
||||
Options.get("InsertPlainNamesInForwardDecls", false)) {}
|
||||
Options.get("InsertPlainNamesInForwardDecls", false)),
|
||||
IgnoredTypes(utils::options::parseStringList(
|
||||
Options.get("IgnoredTypes", DefaultIgnoredTypes))) {}
|
||||
|
||||
void NamedParameterCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
||||
Options.store(Opts, "InsertPlainNamesInForwardDecls",
|
||||
InsertPlainNamesInForwardDecls);
|
||||
Options.store(Opts, "IgnoredTypes",
|
||||
utils::options::serializeStringList(IgnoredTypes));
|
||||
}
|
||||
|
||||
void NamedParameterCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||
|
|
@ -75,6 +108,15 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
|
|||
if (Parm->getType().getCanonicalType()->isNullPtrType())
|
||||
continue;
|
||||
|
||||
// Skip the types configured by the IgnoredTypes option (e.g. standard
|
||||
// tag dispatch types).
|
||||
if (const auto *Record =
|
||||
Parm->getType().getCanonicalType()->getAsCXXRecordDecl()) {
|
||||
const std::string QName = Record->getQualifiedNameAsString();
|
||||
if (llvm::is_contained(IgnoredTypes, QName))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for comments. We explicitly want to allow idioms like
|
||||
// void foo(int /*unused*/)
|
||||
const char *Begin = SM.getCharacterData(Parm->getBeginLoc());
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public:
|
|||
|
||||
private:
|
||||
const bool InsertPlainNamesInForwardDecls;
|
||||
const std::vector<StringRef> IgnoredTypes;
|
||||
};
|
||||
|
||||
} // namespace clang::tidy::readability
|
||||
|
|
|
|||
|
|
@ -103,6 +103,13 @@ New check aliases
|
|||
Changes in existing checks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Improved :doc:`readability-named-parameter
|
||||
<clang-tidy/checks/readability/named-parameter>` check by ignoring
|
||||
standard tag types (e.g. ``std::in_place_t``, ``std::allocator_arg_t``,
|
||||
``std::nothrow_t``, iterator tags, lock tags, etc.) that are used
|
||||
exclusively for overload resolution. Added the :option:`IgnoredTypes`
|
||||
option to allow customizing the set of ignored types.
|
||||
|
||||
Removed checks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ function definition.
|
|||
|
||||
Corresponding cpplint.py check name: `readability/function`.
|
||||
|
||||
The check ignores parameters whose types are standard tag types (e.g.
|
||||
``std::in_place_t``, ``std::allocator_arg_t``, ``std::nothrow_t``,
|
||||
iterator tags, lock tags, etc.). The set of ignored types can be customized
|
||||
with the :option:`IgnoredTypes` option.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
|
|
@ -33,3 +38,36 @@ Options
|
|||
If set to `true`, the check will insert parameter names without comments for
|
||||
forward declarations only. Otherwise, the check will insert parameter names
|
||||
as comments (e.g., ``/*param*/``). Default is `false`.
|
||||
|
||||
.. option:: IgnoredTypes
|
||||
|
||||
A semicolon-separated list of fully-qualified type names whose parameters
|
||||
do not need to be named (for example, tag dispatch types, iterator tags,
|
||||
etc.). Defaults to the standard tag types:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
std::adopt_lock_t
|
||||
std::allocator_arg_t
|
||||
std::bidirectional_iterator_tag
|
||||
std::contiguous_iterator_tag
|
||||
std::default_sentinel_t
|
||||
std::defer_lock_t
|
||||
std::destroying_delete_t
|
||||
std::forward_iterator_tag
|
||||
std::from_range_t
|
||||
std::in_place_index_t
|
||||
std::in_place_t
|
||||
std::in_place_type_t
|
||||
std::input_iterator_tag
|
||||
std::nothrow_t
|
||||
std::nostopstate_t
|
||||
std::nullopt_t
|
||||
std::output_iterator_tag
|
||||
std::piecewise_construct_t
|
||||
std::random_access_iterator_tag
|
||||
std::sorted_equivalent_t
|
||||
std::sorted_unique_t
|
||||
std::try_to_lock_t
|
||||
std::unexpect_t
|
||||
std::unreachable_sentinel_t
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %check_clang_tidy %s readability-named-parameter %t -- \
|
||||
// RUN: -config="{CheckOptions: [{key: readability-named-parameter.IgnoredTypes, value: 'MyCustomTag'}]}"
|
||||
|
||||
struct MyCustomTag {};
|
||||
struct OtherTag {};
|
||||
|
||||
// MyCustomTag is in the custom IgnoredTypes list, so it should not warn.
|
||||
void f_custom(MyCustomTag) {}
|
||||
|
||||
// OtherTag is NOT in the custom list, so it should warn.
|
||||
void f_other(OtherTag) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void f_other(OtherTag /*unused*/) {}
|
||||
|
||||
// int is not in the custom list either, so it should warn.
|
||||
void f_int(int) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void f_int(int /*unused*/) {}
|
||||
|
||||
// Verify the default std types are NOT ignored when a custom list replaces them.
|
||||
namespace std { struct in_place_t {}; }
|
||||
void f_in_place(std::in_place_t) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void f_in_place(std::in_place_t /*unused*/) {}
|
||||
|
|
@ -161,10 +161,68 @@ void MockFunction(Unused, int q, Unused) {
|
|||
|
||||
namespace std {
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
struct adopt_lock_t {};
|
||||
struct allocator_arg_t {};
|
||||
struct bidirectional_iterator_tag {};
|
||||
struct contiguous_iterator_tag {};
|
||||
struct default_sentinel_t {};
|
||||
struct defer_lock_t {};
|
||||
struct destroying_delete_t {};
|
||||
struct forward_iterator_tag {};
|
||||
struct from_range_t {};
|
||||
template<unsigned I> struct in_place_index_t {};
|
||||
struct in_place_t {};
|
||||
template<class T> struct in_place_type_t {};
|
||||
struct input_iterator_tag {};
|
||||
struct nothrow_t {};
|
||||
struct nostopstate_t {};
|
||||
struct nullopt_t {};
|
||||
struct output_iterator_tag {};
|
||||
struct piecewise_construct_t {};
|
||||
struct random_access_iterator_tag {};
|
||||
struct sorted_equivalent_t {};
|
||||
struct sorted_unique_t {};
|
||||
struct try_to_lock_t {};
|
||||
struct unexpect_t {};
|
||||
struct unreachable_sentinel_t {};
|
||||
}
|
||||
|
||||
void f(std::nullptr_t) {}
|
||||
|
||||
// Standard tag dispatch types should not trigger warnings.
|
||||
void f_adopt_lock(std::adopt_lock_t) {}
|
||||
void f_allocator_arg(std::allocator_arg_t) {}
|
||||
void f_bidir_iter(std::bidirectional_iterator_tag) {}
|
||||
void f_contig_iter(std::contiguous_iterator_tag) {}
|
||||
void f_default_sentinel(std::default_sentinel_t) {}
|
||||
void f_defer_lock(std::defer_lock_t) {}
|
||||
void f_destroying(std::destroying_delete_t) {}
|
||||
void f_forward_iter(std::forward_iterator_tag) {}
|
||||
void f_from_range(std::from_range_t) {}
|
||||
void f_in_place_index(std::in_place_index_t<0>) {}
|
||||
void f_in_place(std::in_place_t) {}
|
||||
void f_in_place_type(std::in_place_type_t<int>) {}
|
||||
void f_input_iter(std::input_iterator_tag) {}
|
||||
void f_nothrow(std::nothrow_t) {}
|
||||
void f_nostopstate(std::nostopstate_t) {}
|
||||
void f_nullopt(std::nullopt_t) {}
|
||||
void f_output_iter(std::output_iterator_tag) {}
|
||||
void f_piecewise(std::piecewise_construct_t) {}
|
||||
void f_random_iter(std::random_access_iterator_tag) {}
|
||||
void f_sorted_equivalent(std::sorted_equivalent_t) {}
|
||||
void f_sorted_unique(std::sorted_unique_t) {}
|
||||
void f_try_to_lock(std::try_to_lock_t) {}
|
||||
void f_unexpect(std::unexpect_t) {}
|
||||
void f_unreachable_sentinel(std::unreachable_sentinel_t) {}
|
||||
|
||||
// A type not in the IgnoredTypes list should still trigger a warning.
|
||||
struct NotATag {};
|
||||
void f_not_a_tag(NotATag) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES: void f_not_a_tag(NotATag /*unused*/) {}
|
||||
// CHECK-MESSAGES-PLAIN-NAMES: :[[@LINE-3]]:25: warning: all parameters should be named in a function
|
||||
// CHECK-FIXES-PLAIN-NAMES: void f_not_a_tag(NotATag /*unused*/) {}
|
||||
|
||||
typedef void (F)(int);
|
||||
F f;
|
||||
void f(int x) {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue