[clang-tools-extra] [clang-tide] added `AllowedTypes` option to `readability-qualified-auto` check (PR #136571)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 21 08:31:38 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tools-extra
Author: Baranov Victor (vbvictor)
<details>
<summary>Changes</summary>
Added `AllowedTypes` option to `readability-qualified-auto` check
Fixes https://github.com/llvm/llvm-project/issues/63461.
---
Full diff: https://github.com/llvm/llvm-project/pull/136571.diff
5 Files Affected:
- (modified) clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp (+22-5)
- (modified) clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h (+2-3)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4)
- (modified) clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst (+14)
- (modified) clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp (+146-1)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/136571
More information about the cfe-commits
mailing list