Skip to content

Commit b545713

Browse files
committed
[clang-tidy] offer option to check sugared types in avoid-c-arrays check
There are use cases where people need to diagnose also sugared types, such as type aliases, decltypes or template parameter types, as use of C-Style arrays in case their referenced type falls into such category. Hence, we provide an opt-in option for clang-tidy's modernize-avoid-c-arrays checker to acheive that, if desired.
1 parent 7207300 commit b545713

File tree

4 files changed

+161
-7
lines changed

4 files changed

+161
-7
lines changed

clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) {
2121
return Node.getBeginLoc().isValid();
2222
}
2323

24-
AST_MATCHER_P(clang::TypeLoc, hasType,
25-
clang::ast_matchers::internal::Matcher<clang::Type>,
26-
InnerMatcher) {
24+
AST_MATCHER_P(clang::TypeLoc, hasArrayType, bool, CheckSugaredTypes) {
2725
const clang::Type *TypeNode = Node.getTypePtr();
28-
return TypeNode != nullptr &&
29-
InnerMatcher.matches(*TypeNode, Finder, Builder);
26+
if (CheckSugaredTypes && TypeNode != nullptr) {
27+
TypeNode = TypeNode->getUnqualifiedDesugaredType();
28+
}
29+
return TypeNode != nullptr && arrayType().matches(*TypeNode, Finder, Builder);
3030
}
3131

3232
AST_MATCHER(clang::RecordDecl, isExternCContext) {
@@ -43,7 +43,8 @@ AST_MATCHER(clang::ParmVarDecl, isArgvOfMain) {
4343

4444
AvoidCArraysCheck::AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context)
4545
: ClangTidyCheck(Name, Context),
46-
AllowStringArrays(Options.get("AllowStringArrays", false)) {}
46+
AllowStringArrays(Options.get("AllowStringArrays", false)),
47+
CheckSugaredTypes(Options.get("CheckSugaredTypes", false)) {}
4748

4849
void AvoidCArraysCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
4950
Options.store(Opts, "AllowStringArrays", AllowStringArrays);
@@ -60,7 +61,7 @@ void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) {
6061
unless(parmVarDecl())))));
6162

6263
Finder->addMatcher(
63-
typeLoc(hasValidBeginLoc(), hasType(arrayType()),
64+
typeLoc(hasValidBeginLoc(), hasArrayType(CheckSugaredTypes),
6465
optionally(hasParent(parmVarDecl().bind("param_decl"))),
6566
unless(anyOf(hasParent(parmVarDecl(isArgvOfMain())),
6667
hasParent(varDecl(isExternC())),
@@ -96,6 +97,26 @@ void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) {
9697
diag(ArrayType->getBeginLoc(),
9798
"do not declare %select{C-style|C VLA}0 arrays, use %1 instead")
9899
<< IsVLA << llvm::join(RecommendTypes, " or ");
100+
101+
if (CheckSugaredTypes) {
102+
PrintingPolicy PrintPolicy{getLangOpts()};
103+
PrintPolicy.SuppressTagKeyword = true;
104+
105+
const auto TypeName = ArrayType->getType().getAsString(PrintPolicy);
106+
const auto DesugaredTypeName = ArrayType->getType()
107+
->getUnqualifiedDesugaredType()
108+
->getCanonicalTypeInternal()
109+
.getAsString(PrintPolicy);
110+
if (TypeName != DesugaredTypeName) {
111+
diag(ArrayType->getBeginLoc(), "declared type '%0' resolves to '%1'",
112+
DiagnosticIDs::Note)
113+
<< TypeName << DesugaredTypeName;
114+
} else {
115+
diag(ArrayType->getBeginLoc(), "array type '%0' here",
116+
DiagnosticIDs::Note)
117+
<< TypeName;
118+
}
119+
}
99120
}
100121

101122
} // namespace clang::tidy::modernize

clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class AvoidCArraysCheck : public ClangTidyCheck {
3232

3333
private:
3434
const bool AllowStringArrays;
35+
const bool CheckSugaredTypes;
3536
};
3637

3738
} // namespace clang::tidy::modernize

clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-c-arrays.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,9 @@ can be either ``char* argv[]`` or ``char** argv``, but cannot be
7272
.. code:: c++
7373

7474
const char name[] = "Some name";
75+
76+
.. option:: CheckSugaredTypes
77+
78+
When set to `true` (default is `false`), type aliases, decltypes as well as
79+
template parameter types will get resolved and diagnosed as usage of
80+
C-style array in case their underlying type resolves to one.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t -- \
2+
// RUN: -config='{CheckOptions: { modernize-avoid-c-arrays.CheckSugaredTypes: true }}'
3+
4+
int a[] = {1, 2};
5+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead
6+
7+
int b[1];
8+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead
9+
10+
void foo() {
11+
int c[b[0]];
12+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C VLA arrays, use 'std::vector' instead
13+
14+
using d = decltype(c);
15+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not declare C VLA arrays, use 'std::vector' instead
16+
// CHECK-MESSAGES: :[[@LINE-2]]:13: note: declared type 'decltype(c)' resolves to 'int[b[0]]'
17+
18+
d e;
19+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C VLA arrays, use 'std::vector' instead
20+
// CHECK-MESSAGES: :[[@LINE-2]]:3: note: declared type 'd' resolves to 'int[b[0]]'
21+
}
22+
23+
template <typename T, int Size>
24+
class array {
25+
T d[Size];
26+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead
27+
28+
int e[1];
29+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead
30+
};
31+
32+
array<int[4], 2> d;
33+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use 'std::array' instead
34+
35+
using k = int[4];
36+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not declare C-style arrays, use 'std::array' instead
37+
38+
array<k, 2> dk;
39+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use 'std::array' instead
40+
// CHECK-MESSAGES: :[[@LINE-2]]:7: note: declared type 'k' resolves to 'int[4]'
41+
42+
template <typename T>
43+
class unique_ptr {
44+
T *d;
45+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead
46+
// CHECK-MESSAGES: :[[@LINE-2]]:3: note: array type 'int[]' here
47+
48+
int e[1];
49+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead
50+
};
51+
52+
unique_ptr<int[]> d2;
53+
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use 'std::array' instead
54+
55+
using k2 = int[];
56+
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use 'std::array' instead
57+
58+
unique_ptr<k2> dk2;
59+
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use 'std::array' instead
60+
// CHECK-MESSAGES: :[[@LINE-2]]:12: note: declared type 'k2' resolves to 'int[]'
61+
62+
// Some header
63+
extern "C" {
64+
65+
int f[] = {1, 2};
66+
67+
int j[1];
68+
69+
inline void bar() {
70+
{
71+
int j[j[0]];
72+
}
73+
}
74+
75+
extern "C++" {
76+
int f3[] = {1, 2};
77+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead
78+
79+
int j3[1];
80+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead
81+
82+
struct Foo {
83+
int f3[3] = {1, 2};
84+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead
85+
86+
int j3[1];
87+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use 'std::array' instead
88+
};
89+
}
90+
91+
struct Bar {
92+
93+
int f[3] = {1, 2};
94+
95+
int j[1];
96+
};
97+
}
98+
99+
const char name[] = "Some string";
100+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
101+
102+
void takeCharArray(const char name[]);
103+
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use 'std::array' or 'std::vector' instead [modernize-avoid-c-arrays]
104+
105+
using MyIntArray = int[10];
106+
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
107+
108+
using MyIntArray2D = MyIntArray[10];
109+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
110+
// CHECK-MESSAGES: :[[@LINE-2]]:22: note: declared type 'MyIntArray[10]' resolves to 'int[10][10]'
111+
112+
using MyIntArray3D = MyIntArray2D[10];
113+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
114+
// CHECK-MESSAGES: :[[@LINE-2]]:22: note: declared type 'MyIntArray2D[10]' resolves to 'int[10][10][10]'
115+
116+
MyIntArray3D array3D;
117+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
118+
// CHECK-MESSAGES: :[[@LINE-2]]:1: note: declared type 'MyIntArray3D' resolves to 'int[10][10][10]'
119+
120+
MyIntArray2D array2D;
121+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
122+
// CHECK-MESSAGES: :[[@LINE-2]]:1: note: declared type 'MyIntArray2D' resolves to 'int[10][10]'
123+
124+
MyIntArray array1D;
125+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use 'std::array' instead [modernize-avoid-c-arrays]
126+
// CHECK-MESSAGES: :[[@LINE-2]]:1: note: declared type 'MyIntArray' resolves to 'int[10]'

0 commit comments

Comments
 (0)