https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/136571
>From 95be4b44cc7ad8f9b30b020ba3083a5267a65202 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Mon, 21 Apr 2025 18:29:28 +0300 Subject: [PATCH 1/2] added Allowed types to qualified-auto --- .../readability/QualifiedAutoCheck.cpp | 27 +++- .../readability/QualifiedAutoCheck.h | 5 +- clang-tools-extra/docs/ReleaseNotes.rst | 4 + .../checks/readability/qualified-auto.rst | 14 ++ .../checkers/readability/qualified-auto.cpp | 147 +++++++++++++++++- 5 files changed, 188 insertions(+), 9 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index e843c593a92cc..00999ee8310c1 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -8,6 +8,8 @@ #include "QualifiedAutoCheck.h" #include "../utils/LexerUtils.h" +#include "../utils/Matchers.h" +#include "../utils/OptionsUtils.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "llvm/ADT/SmallVector.h" #include <optional> @@ -100,8 +102,17 @@ bool isAutoPointerConst(QualType QType) { } // namespace +QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + AddConstToQualified(Options.get("AddConstToQualified", true)), + AllowedTypes( + utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} + void QualifiedAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "AddConstToQualified", AddConstToQualified); + Options.store(Opts, "AllowedTypes", + utils::options::serializeStringList(AllowedTypes)); } void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { @@ -124,20 +135,26 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { auto IsBoundToType = refersToType(equalsBoundNode("type")); auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); - auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) { + auto IsAutoDeducedToPointer = [](const std::vector<StringRef> &AllowedTypes, + const auto &...InnerMatchers) { return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))))); + hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))), + unless(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))), + unless(pointerType(pointee(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); }; Finder->addMatcher( - ExplicitSingleVarDecl(hasType(IsAutoDeducedToPointer(UnlessFunctionType)), - "auto"), + ExplicitSingleVarDecl( + hasType(IsAutoDeducedToPointer(AllowedTypes, UnlessFunctionType)), + "auto"), this); Finder->addMatcher( ExplicitSingleVarDeclInTemplate( allOf(hasType(IsAutoDeducedToPointer( - hasUnqualifiedType(qualType().bind("type")), + AllowedTypes, hasUnqualifiedType(qualType().bind("type")), UnlessFunctionType)), anyOf(hasAncestor( functionDecl(hasAnyTemplateArgument(IsBoundToType))), diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h index dae9add48e3d7..187a4cd6ee614 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h @@ -21,9 +21,7 @@ namespace clang::tidy::readability { /// http://clang.llvm.org/extra/clang-tidy/checks/readability/qualified-auto.html class QualifiedAutoCheck : public ClangTidyCheck { public: - QualifiedAutoCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - AddConstToQualified(Options.get("AddConstToQualified", true)) {} + QualifiedAutoCheck(StringRef Name, ClangTidyContext *Context); bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus11; } @@ -33,6 +31,7 @@ class QualifiedAutoCheck : public ClangTidyCheck { private: const bool AddConstToQualified; + const std::vector<StringRef> AllowedTypes; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 761c1d3a80359..d3e4530535638 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -204,6 +204,10 @@ Changes in existing checks tolerating fix-it breaking compilation when functions is used as pointers to avoid matching usage of functions within the current compilation unit. +- Improved :doc:`readability-qualified-auto + <clang-tidy/checks/readability/qualified-auto>` check by adding the option + `AllowedTypes`, that excludes specified types from adding qualifiers. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst index 9bc2c1295d3ec..efa085719643c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst @@ -82,3 +82,17 @@ Otherwise it will be transformed into: const auto &Foo3 = cast<const int &>(Bar3); Note in the LLVM alias, the default value is `false`. + +.. option:: AllowedTypes + + A semicolon-separated list of names of types to ignore when ``auto`` is + deduced to that type or a pointer to that type. Note that this distinguishes + type aliases from the original type, so specifying e.g. ``my_int`` will not + suppress reports about ``int`` even if it is defined as a ``typedef`` alias + for ``int``. Regular expressions are accepted, e.g. ``[Rr]ef(erence)?$`` + matches every type with suffix ``Ref``, ``ref``, ``Reference`` and + ``reference``. If a name in the list contains the sequence `::` it is matched + against the qualified type name (i.e. ``namespace::Type``), otherwise it is + matched against only the type name (i.e. ``Type``). E.g. to suppress reports + for ``std::array`` iterators use `std::array<.*>::(const_)?iterator` string. + The default is an empty string. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp index 6cc794882859f..7c25b853bfa0c 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp @@ -1,4 +1,7 @@ -// RUN: %check_clang_tidy %s readability-qualified-auto %t +// RUN: %check_clang_tidy %s readability-qualified-auto %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-qualified-auto.AllowedTypes: "[iI]terator$;my::ns::Ignored1;std::array<.*>::Ignored2;MyIgnoredPtr" \ +// RUN: }}' namespace typedefs { typedef int *MyPtr; @@ -238,3 +241,145 @@ void baz() { auto &MyFunctionRef2 = *getPtrFunction(); } + +namespace std { + +template<typename T, int N> +struct array { + typedef T value_type; + + typedef value_type* iterator; + typedef value_type* Iterator; + using using_iterator = T*; + typedef const value_type* const_iterator; + typedef const value_type* constIterator; + + struct Ignored2 {}; + using NotIgnored2 = Ignored2; + + iterator begin() { return nullptr; } + const_iterator begin() const { return nullptr; } + iterator end() { return nullptr; } + const_iterator end() const { return nullptr; } +}; + +struct Iterator {}; + +struct Ignored2 {}; // should not be ignored + +} // namespace std + +typedef std::Iterator iterator; + +namespace my { +namespace ns { + +struct Ignored1 {}; + +using NotIgnored1 = Ignored1; +typedef Ignored1 NotIgnored2; + +} // namespace ns + +struct Ignored1 {}; // should not be ignored + +} // namespace my + +typedef int *MyIgnoredPtr; +MyIgnoredPtr getIgnoredPtr(); + +void ignored_types() { + auto ignored_ptr = getIgnoredPtr(); + // CHECK-MESSAGES-NOT: warning: 'auto ignored_ptr' can be declared as 'auto *ignored_ptr' + // CHECK-FIXES-NOT: auto *ignored_ptr = getIgnoredPtr(); + + std::array<int, 4> arr; + std::array<int, 4> carr; + + auto it1 = arr.begin(); + // CHECK-MESSAGES-NOT: warning: 'auto it' can be declared as 'auto *it' + // CHECK-FIXES-NOT: auto *it = vec.it_begin(); + + auto it2 = carr.begin(); + // CHECK-MESSAGES-NOT: warning: 'auto it2' can be declared as 'auto *it2' + // CHECK-FIXES-NOT: auto *it2 = carr.begin(); + + auto it3 = std::array<int, 4>::iterator{}; + // CHECK-MESSAGES-NOT: warning: 'auto it3' can be declared as 'auto *it3' + // CHECK-FIXES-NOT: auto *it3 = std::array<int, 4>::iterator{}; + + auto it4 = std::array<int, 4>::Iterator{}; + // CHECK-MESSAGES-NOT: warning: 'auto it4' can be declared as 'auto *it4' + // CHECK-FIXES-NOT: auto *it4 = std::array<int, 4>::Iterator{}; + + auto it5 = std::array<int, 4>::using_iterator{}; + // CHECK-MESSAGES-NOT: warning: 'auto it5' can be declared as 'auto *it5' + // CHECK-FIXES-NOT: auto *it5 = std::array<int, 4>::using_iterator{}; + + auto it6 = std::array<int, 4>::const_iterator{}; + // CHECK-MESSAGES-NOT: warning: 'auto it6' can be declared as 'auto *it6' + // CHECK-FIXES-NOT: auto *it6 = std::array<int, 4>::const_iterator{}; + + auto it7 = std::array<int, 4>::constIterator{}; + // CHECK-MESSAGES-NOT: warning: 'auto it7' can be declared as 'auto *it7' + // CHECK-FIXES-NOT: auto *it7 = std::array<int, 4>::constIterator{}; + + auto it8 = new std::Iterator(); + // CHECK-MESSAGES-NOT: warning: 'auto it8' can be declared as 'auto *it8' + // CHECK-FIXES-NOT: auto *it8 = new std::Iterator(); + + auto it9 = new iterator(); + // CHECK-MESSAGES-NOT: warning: 'auto it9' can be declared as 'auto *it9' + // CHECK-FIXES-NOT: auto *it9 = new iterator(); + + auto arr_ignored2 = new std::array<int, 4>::Ignored2(); + // CHECK-MESSAGES-NOT: warning: 'auto arr_ignored2' can be declared as 'auto *arr_ignored2' + // CHECK-FIXES-NOT: auto *arr_ignored2 = new std::array<int, 4>::Ignored2(); + + auto arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto arr_not_ignored2' can be declared as 'auto *arr_not_ignored2' + // CHECK-FIXES: auto *arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); + + auto not_ignored2 = new std::Ignored2(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored2' can be declared as 'auto *not_ignored2' + // CHECK-FIXES: auto *not_ignored2 = new std::Ignored2(); + + auto ignored1 = new my::ns::Ignored1(); + // CHECK-MESSAGES-NOT: warning: 'auto ignored1' can be declared as 'auto *ignored1' + // CHECK-FIXES-NOT: auto *ignored1 = new my::ns::Ignored1(); + + auto not_ignored1 = new my::ns::NotIgnored1(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored1' can be declared as 'auto *not_ignored1' + // CHECK-FIXES: auto *not_ignored1 = new my::ns::NotIgnored1(); + + auto not2_ignored1 = new my::ns::NotIgnored2(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not2_ignored1' can be declared as 'auto *not2_ignored1' + // CHECK-FIXES: auto *not2_ignored1 = new my::ns::NotIgnored2(); + + auto not3_ignored1 = new my::Ignored1(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not3_ignored1' can be declared as 'auto *not3_ignored1' + // CHECK-FIXES: auto *not3_ignored1 = new my::Ignored1(); +} + +template <typename T> +void ignored_types_template(std::array<T, 4> arr, const std::array<T, 4>& carr) { + auto it1 = arr.begin(); + // CHECK-MESSAGES-NOT: warning: 'auto it' can be declared as 'auto *it' + // CHECK-FIXES-NOT: auto *it = arr.it_begin(); + + auto it2 = carr.begin(); + // CHECK-MESSAGES-NOT: warning: 'auto it2' can be declared as 'auto *it2' + // CHECK-FIXES-NOT: auto *it2 = carr.begin(); + + for (auto Data : arr) { + // CHECK-MESSAGES-NOT: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-NOT: {{^}} for (auto *Data : MClassTemplate) { + change(*Data); + } + + for (auto Data : carr) { + // CHECK-MESSAGES-NOT: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-NOT: {{^}} for (const auto *Data : MClassTemplate) { + change(*Data); + } +} \ No newline at end of file >From 39d3987bc459c483da87b1e25763952ce96c4736 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Mon, 21 Apr 2025 18:32:17 +0300 Subject: [PATCH 2/2] added newline to end of test file --- .../test/clang-tidy/checkers/readability/qualified-auto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp index 7c25b853bfa0c..77afdcafef9dd 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp @@ -382,4 +382,4 @@ void ignored_types_template(std::array<T, 4> arr, const std::array<T, 4>& carr) // CHECK-FIXES-NOT: {{^}} for (const auto *Data : MClassTemplate) { change(*Data); } -} \ No newline at end of file +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits