Skip to content

Commit 40afd71

Browse files
vbvictorsivan-shani
authored andcommitted
[clang-tidy] added AllowedTypes option to readability-qualified-auto check (llvm#136571)
Added `AllowedTypes` option to `readability-qualified-auto` check Fixes llvm#63461.
1 parent abd6da3 commit 40afd71

File tree

5 files changed

+188
-9
lines changed

5 files changed

+188
-9
lines changed

clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "QualifiedAutoCheck.h"
1010
#include "../utils/LexerUtils.h"
11+
#include "../utils/Matchers.h"
12+
#include "../utils/OptionsUtils.h"
1113
#include "clang/ASTMatchers/ASTMatchers.h"
1214
#include "llvm/ADT/SmallVector.h"
1315
#include <optional>
@@ -100,8 +102,17 @@ bool isAutoPointerConst(QualType QType) {
100102

101103
} // namespace
102104

105+
QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name,
106+
ClangTidyContext *Context)
107+
: ClangTidyCheck(Name, Context),
108+
AddConstToQualified(Options.get("AddConstToQualified", true)),
109+
AllowedTypes(
110+
utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
111+
103112
void QualifiedAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
104113
Options.store(Opts, "AddConstToQualified", AddConstToQualified);
114+
Options.store(Opts, "AllowedTypes",
115+
utils::options::serializeStringList(AllowedTypes));
105116
}
106117

107118
void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) {
@@ -124,20 +135,26 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) {
124135

125136
auto IsBoundToType = refersToType(equalsBoundNode("type"));
126137
auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType()));
127-
auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) {
138+
auto IsAutoDeducedToPointer = [](const std::vector<StringRef> &AllowedTypes,
139+
const auto &...InnerMatchers) {
128140
return autoType(hasDeducedType(
129-
hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))));
141+
hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))),
142+
unless(hasUnqualifiedType(
143+
matchers::matchesAnyListedTypeName(AllowedTypes, false))),
144+
unless(pointerType(pointee(hasUnqualifiedType(
145+
matchers::matchesAnyListedTypeName(AllowedTypes, false)))))));
130146
};
131147

132148
Finder->addMatcher(
133-
ExplicitSingleVarDecl(hasType(IsAutoDeducedToPointer(UnlessFunctionType)),
134-
"auto"),
149+
ExplicitSingleVarDecl(
150+
hasType(IsAutoDeducedToPointer(AllowedTypes, UnlessFunctionType)),
151+
"auto"),
135152
this);
136153

137154
Finder->addMatcher(
138155
ExplicitSingleVarDeclInTemplate(
139156
allOf(hasType(IsAutoDeducedToPointer(
140-
hasUnqualifiedType(qualType().bind("type")),
157+
AllowedTypes, hasUnqualifiedType(qualType().bind("type")),
141158
UnlessFunctionType)),
142159
anyOf(hasAncestor(
143160
functionDecl(hasAnyTemplateArgument(IsBoundToType))),

clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ namespace clang::tidy::readability {
2121
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/qualified-auto.html
2222
class QualifiedAutoCheck : public ClangTidyCheck {
2323
public:
24-
QualifiedAutoCheck(StringRef Name, ClangTidyContext *Context)
25-
: ClangTidyCheck(Name, Context),
26-
AddConstToQualified(Options.get("AddConstToQualified", true)) {}
24+
QualifiedAutoCheck(StringRef Name, ClangTidyContext *Context);
2725
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
2826
return LangOpts.CPlusPlus11;
2927
}
@@ -33,6 +31,7 @@ class QualifiedAutoCheck : public ClangTidyCheck {
3331

3432
private:
3533
const bool AddConstToQualified;
34+
const std::vector<StringRef> AllowedTypes;
3635
};
3736

3837
} // namespace clang::tidy::readability

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ Changes in existing checks
239239
tolerating fix-it breaking compilation when functions is used as pointers
240240
to avoid matching usage of functions within the current compilation unit.
241241

242+
- Improved :doc:`readability-qualified-auto
243+
<clang-tidy/checks/readability/qualified-auto>` check by adding the option
244+
`AllowedTypes`, that excludes specified types from adding qualifiers.
245+
242246
Removed checks
243247
^^^^^^^^^^^^^^
244248

clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,17 @@ Otherwise it will be transformed into:
8282
const auto &Foo3 = cast<const int &>(Bar3);
8383
8484
Note in the LLVM alias, the default value is `false`.
85+
86+
.. option:: AllowedTypes
87+
88+
A semicolon-separated list of names of types to ignore when ``auto`` is
89+
deduced to that type or a pointer to that type. Note that this distinguishes
90+
type aliases from the original type, so specifying e.g. ``my_int`` will not
91+
suppress reports about ``int`` even if it is defined as a ``typedef`` alias
92+
for ``int``. Regular expressions are accepted, e.g. ``[Rr]ef(erence)?$``
93+
matches every type with suffix ``Ref``, ``ref``, ``Reference`` and
94+
``reference``. If a name in the list contains the sequence `::` it is matched
95+
against the qualified type name (i.e. ``namespace::Type``), otherwise it is
96+
matched against only the type name (i.e. ``Type``). E.g. to suppress reports
97+
for ``std::array`` iterators use `std::array<.*>::(const_)?iterator` string.
98+
The default is an empty string.

clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %check_clang_tidy %s readability-qualified-auto %t
1+
// RUN: %check_clang_tidy %s readability-qualified-auto %t \
2+
// RUN: -config='{CheckOptions: { \
3+
// RUN: readability-qualified-auto.AllowedTypes: "[iI]terator$;my::ns::Ignored1;std::array<.*>::Ignored2;MyIgnoredPtr" \
4+
// RUN: }}'
25

36
namespace typedefs {
47
typedef int *MyPtr;
@@ -238,3 +241,145 @@ void baz() {
238241

239242
auto &MyFunctionRef2 = *getPtrFunction();
240243
}
244+
245+
namespace std {
246+
247+
template<typename T, int N>
248+
struct array {
249+
typedef T value_type;
250+
251+
typedef value_type* iterator;
252+
typedef value_type* Iterator;
253+
using using_iterator = T*;
254+
typedef const value_type* const_iterator;
255+
typedef const value_type* constIterator;
256+
257+
struct Ignored2 {};
258+
using NotIgnored2 = Ignored2;
259+
260+
iterator begin() { return nullptr; }
261+
const_iterator begin() const { return nullptr; }
262+
iterator end() { return nullptr; }
263+
const_iterator end() const { return nullptr; }
264+
};
265+
266+
struct Iterator {};
267+
268+
struct Ignored2 {}; // should not be ignored
269+
270+
} // namespace std
271+
272+
typedef std::Iterator iterator;
273+
274+
namespace my {
275+
namespace ns {
276+
277+
struct Ignored1 {};
278+
279+
using NotIgnored1 = Ignored1;
280+
typedef Ignored1 NotIgnored2;
281+
282+
} // namespace ns
283+
284+
struct Ignored1 {}; // should not be ignored
285+
286+
} // namespace my
287+
288+
typedef int *MyIgnoredPtr;
289+
MyIgnoredPtr getIgnoredPtr();
290+
291+
void ignored_types() {
292+
auto ignored_ptr = getIgnoredPtr();
293+
// CHECK-MESSAGES-NOT: warning: 'auto ignored_ptr' can be declared as 'auto *ignored_ptr'
294+
// CHECK-FIXES-NOT: auto *ignored_ptr = getIgnoredPtr();
295+
296+
std::array<int, 4> arr;
297+
std::array<int, 4> carr;
298+
299+
auto it1 = arr.begin();
300+
// CHECK-MESSAGES-NOT: warning: 'auto it' can be declared as 'auto *it'
301+
// CHECK-FIXES-NOT: auto *it = vec.it_begin();
302+
303+
auto it2 = carr.begin();
304+
// CHECK-MESSAGES-NOT: warning: 'auto it2' can be declared as 'auto *it2'
305+
// CHECK-FIXES-NOT: auto *it2 = carr.begin();
306+
307+
auto it3 = std::array<int, 4>::iterator{};
308+
// CHECK-MESSAGES-NOT: warning: 'auto it3' can be declared as 'auto *it3'
309+
// CHECK-FIXES-NOT: auto *it3 = std::array<int, 4>::iterator{};
310+
311+
auto it4 = std::array<int, 4>::Iterator{};
312+
// CHECK-MESSAGES-NOT: warning: 'auto it4' can be declared as 'auto *it4'
313+
// CHECK-FIXES-NOT: auto *it4 = std::array<int, 4>::Iterator{};
314+
315+
auto it5 = std::array<int, 4>::using_iterator{};
316+
// CHECK-MESSAGES-NOT: warning: 'auto it5' can be declared as 'auto *it5'
317+
// CHECK-FIXES-NOT: auto *it5 = std::array<int, 4>::using_iterator{};
318+
319+
auto it6 = std::array<int, 4>::const_iterator{};
320+
// CHECK-MESSAGES-NOT: warning: 'auto it6' can be declared as 'auto *it6'
321+
// CHECK-FIXES-NOT: auto *it6 = std::array<int, 4>::const_iterator{};
322+
323+
auto it7 = std::array<int, 4>::constIterator{};
324+
// CHECK-MESSAGES-NOT: warning: 'auto it7' can be declared as 'auto *it7'
325+
// CHECK-FIXES-NOT: auto *it7 = std::array<int, 4>::constIterator{};
326+
327+
auto it8 = new std::Iterator();
328+
// CHECK-MESSAGES-NOT: warning: 'auto it8' can be declared as 'auto *it8'
329+
// CHECK-FIXES-NOT: auto *it8 = new std::Iterator();
330+
331+
auto it9 = new iterator();
332+
// CHECK-MESSAGES-NOT: warning: 'auto it9' can be declared as 'auto *it9'
333+
// CHECK-FIXES-NOT: auto *it9 = new iterator();
334+
335+
auto arr_ignored2 = new std::array<int, 4>::Ignored2();
336+
// CHECK-MESSAGES-NOT: warning: 'auto arr_ignored2' can be declared as 'auto *arr_ignored2'
337+
// CHECK-FIXES-NOT: auto *arr_ignored2 = new std::array<int, 4>::Ignored2();
338+
339+
auto arr_not_ignored2 = new std::array<int, 4>::NotIgnored2();
340+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto arr_not_ignored2' can be declared as 'auto *arr_not_ignored2'
341+
// CHECK-FIXES: auto *arr_not_ignored2 = new std::array<int, 4>::NotIgnored2();
342+
343+
auto not_ignored2 = new std::Ignored2();
344+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored2' can be declared as 'auto *not_ignored2'
345+
// CHECK-FIXES: auto *not_ignored2 = new std::Ignored2();
346+
347+
auto ignored1 = new my::ns::Ignored1();
348+
// CHECK-MESSAGES-NOT: warning: 'auto ignored1' can be declared as 'auto *ignored1'
349+
// CHECK-FIXES-NOT: auto *ignored1 = new my::ns::Ignored1();
350+
351+
auto not_ignored1 = new my::ns::NotIgnored1();
352+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored1' can be declared as 'auto *not_ignored1'
353+
// CHECK-FIXES: auto *not_ignored1 = new my::ns::NotIgnored1();
354+
355+
auto not2_ignored1 = new my::ns::NotIgnored2();
356+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not2_ignored1' can be declared as 'auto *not2_ignored1'
357+
// CHECK-FIXES: auto *not2_ignored1 = new my::ns::NotIgnored2();
358+
359+
auto not3_ignored1 = new my::Ignored1();
360+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not3_ignored1' can be declared as 'auto *not3_ignored1'
361+
// CHECK-FIXES: auto *not3_ignored1 = new my::Ignored1();
362+
}
363+
364+
template <typename T>
365+
void ignored_types_template(std::array<T, 4> arr, const std::array<T, 4>& carr) {
366+
auto it1 = arr.begin();
367+
// CHECK-MESSAGES-NOT: warning: 'auto it' can be declared as 'auto *it'
368+
// CHECK-FIXES-NOT: auto *it = arr.it_begin();
369+
370+
auto it2 = carr.begin();
371+
// CHECK-MESSAGES-NOT: warning: 'auto it2' can be declared as 'auto *it2'
372+
// CHECK-FIXES-NOT: auto *it2 = carr.begin();
373+
374+
for (auto Data : arr) {
375+
// CHECK-MESSAGES-NOT: warning: 'auto Data' can be declared as 'auto *Data'
376+
// CHECK-FIXES-NOT: {{^}} for (auto *Data : MClassTemplate) {
377+
change(*Data);
378+
}
379+
380+
for (auto Data : carr) {
381+
// CHECK-MESSAGES-NOT: warning: 'auto Data' can be declared as 'const auto *Data'
382+
// CHECK-FIXES-NOT: {{^}} for (const auto *Data : MClassTemplate) {
383+
change(*Data);
384+
}
385+
}

0 commit comments

Comments
 (0)