Skip to content

Commit 785624b

Browse files
authored
[clang-tidy]suggest use std::span as replacement of c array in C++20 for modernize-avoid-c-arrays (#108555)
The incompleted C-Array in parameter does not own memory. Instead, It is equivalent to pointer. So we should not use `std::array` as recommended modern C++ replacement, but use `std::vector` and `std::span` in C++20
1 parent ca0613e commit 785624b

File tree

8 files changed

+54
-16
lines changed

8 files changed

+54
-16
lines changed

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

+23-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "AvoidCArraysCheck.h"
1010
#include "clang/AST/ASTContext.h"
1111
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
1213

1314
using namespace clang::ast_matchers;
1415

@@ -60,6 +61,7 @@ void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) {
6061

6162
Finder->addMatcher(
6263
typeLoc(hasValidBeginLoc(), hasType(arrayType()),
64+
optionally(hasParent(parmVarDecl().bind("param_decl"))),
6365
unless(anyOf(hasParent(parmVarDecl(isArgvOfMain())),
6466
hasParent(varDecl(isExternC())),
6567
hasParent(fieldDecl(
@@ -72,11 +74,28 @@ void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) {
7274

7375
void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) {
7476
const auto *ArrayType = Result.Nodes.getNodeAs<TypeLoc>("typeloc");
75-
77+
const bool IsInParam =
78+
Result.Nodes.getNodeAs<ParmVarDecl>("param_decl") != nullptr;
79+
const bool IsVLA = ArrayType->getTypePtr()->isVariableArrayType();
80+
enum class RecommendType { Array, Vector, Span };
81+
llvm::SmallVector<const char *> RecommendTypes{};
82+
if (IsVLA) {
83+
RecommendTypes.push_back("std::vector<>");
84+
} else if (ArrayType->getTypePtr()->isIncompleteArrayType() && IsInParam) {
85+
// in function parameter, we also don't know the size of
86+
// IncompleteArrayType.
87+
if (Result.Context->getLangOpts().CPlusPlus20)
88+
RecommendTypes.push_back("std::span<>");
89+
else {
90+
RecommendTypes.push_back("std::array<>");
91+
RecommendTypes.push_back("std::vector<>");
92+
}
93+
} else {
94+
RecommendTypes.push_back("std::array<>");
95+
}
7696
diag(ArrayType->getBeginLoc(),
77-
"do not declare %select{C-style|C VLA}0 arrays, use "
78-
"%select{std::array<>|std::vector<>}0 instead")
79-
<< ArrayType->getTypePtr()->isVariableArrayType();
97+
"do not declare %select{C-style|C VLA}0 arrays, use %1 instead")
98+
<< IsVLA << llvm::join(RecommendTypes, " or ");
8099
}
81100

82101
} // namespace clang::tidy::modernize

clang-tools-extra/docs/ReleaseNotes.rst

+5
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ Changes in existing checks
137137
<clang-tidy/checks/misc/definitions-in-headers>` check by rewording the
138138
diagnostic note that suggests adding ``inline``.
139139

140+
- Improved :doc:`modernize-avoid-c-arrays
141+
<clang-tidy/checks/modernize/avoid-c-arrays>` check to suggest using ``std::span``
142+
as a replacement for parameters of incomplete C array type in C++20 and
143+
``std::array`` or ``std::vector`` before C++20.
144+
140145
- Improved :doc:`modernize-use-std-format
141146
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
142147
member function calls too.

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

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ modernize-avoid-c-arrays
1010
Finds C-style array types and recommend to use ``std::array<>`` /
1111
``std::vector<>``. All types of C arrays are diagnosed.
1212

13+
For incomplete C-style array types appeared in parameters, It would be better to
14+
use ``std::span`` / ``gsl::span`` as replacement.
15+
1316
However, fix-it are potentially dangerous in header files and are therefore not
1417
emitted right now.
1518

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %check_clang_tidy -std=c++20 %s modernize-avoid-c-arrays %t
2+
3+
int f1(int data[], int size) {
4+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not declare C-style arrays, use std::span<> instead
5+
int f4[] = {1, 2};
6+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
7+
}
8+
9+
int f2(int data[100]) {
10+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not declare C-style arrays, use std::array<> instead
11+
}

clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-ignores-main.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t
1+
// RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t
22

33
int not_main(int argc, char *argv[]) {
4-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use std::array<> instead
4+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead
55
int f4[] = {1, 2};
66
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
77
}
@@ -11,7 +11,7 @@ int main(int argc, char *argv[]) {
1111
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
1212

1313
auto not_main = [](int argc, char *argv[]) {
14-
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: do not declare C-style arrays, use std::array<> instead
14+
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead
1515
int f6[] = {1, 2};
1616
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not declare C-style arrays, use std::array<> instead
1717
};
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t -- \
1+
// RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t -- \
22
// RUN: -config='{CheckOptions: { modernize-avoid-c-arrays.AllowStringArrays: true }}'
33

44
const char name[] = "name";
55
const char array[] = {'n', 'a', 'm', 'e', '\0'};
66
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
77

88
void takeCharArray(const char name[]);
9-
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
9+
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead [modernize-avoid-c-arrays]

clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-ignores-three-arg-main.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t
1+
// RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t
22

33
int not_main(int argc, char *argv[], char *argw[]) {
4-
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use std::array<> instead
5-
// CHECK-MESSAGES: :[[@LINE-2]]:38: warning: do not declare C-style arrays, use std::array<> instead
4+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead
5+
// CHECK-MESSAGES: :[[@LINE-2]]:38: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead
66
int f4[] = {1, 2};
77
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
88
}
@@ -12,8 +12,8 @@ int main(int argc, char *argv[], char *argw[]) {
1212
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
1313

1414
auto not_main = [](int argc, char *argv[], char *argw[]) {
15-
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: do not declare C-style arrays, use std::array<> instead
16-
// CHECK-MESSAGES: :[[@LINE-2]]:46: warning: do not declare C-style arrays, use std::array<> instead
15+
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead
16+
// CHECK-MESSAGES: :[[@LINE-2]]:46: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead
1717
int f6[] = {1, 2};
1818
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not declare C-style arrays, use std::array<> instead
1919
};

clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t
1+
// RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t
22

33
int a[] = {1, 2};
44
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
@@ -91,4 +91,4 @@ const char name[] = "Some string";
9191
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
9292

9393
void takeCharArray(const char name[]);
94-
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
94+
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> or std::vector<> instead [modernize-avoid-c-arrays]

0 commit comments

Comments
 (0)