[clang-tools-extra] [clang-tidy] offer option to check sugared types in avoid-c-arrays check (PR #131468)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 15 13:09:34 PDT 2025
https://github.com/stmuench created https://github.com/llvm/llvm-project/pull/131468
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.
>From 088fe6fb31b16508118786e73c4decef57d287bf Mon Sep 17 00:00:00 2001
From: stmuench <stmuench at gmx.net>
Date: Sat, 15 Mar 2025 21:00:52 +0100
Subject: [PATCH] [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.
---
.../modernize/AvoidCArraysCheck.cpp | 35 ++++-
.../clang-tidy/modernize/AvoidCArraysCheck.h | 1 +
.../checks/modernize/avoid-c-arrays.rst | 6 +
.../avoid-c-arrays-check-sugared-types.cpp | 125 ++++++++++++++++++
4 files changed, 160 insertions(+), 7 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-check-sugared-types.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.cpp
index 0804aa76d953c..d9f708c9921ac 100644
--- a/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.cpp
@@ -21,12 +21,12 @@ AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) {
return Node.getBeginLoc().isValid();
}
-AST_MATCHER_P(clang::TypeLoc, hasType,
- clang::ast_matchers::internal::Matcher<clang::Type>,
- InnerMatcher) {
+AST_MATCHER_P(clang::TypeLoc, hasArrayType, bool, CheckSugaredTypes) {
const clang::Type *TypeNode = Node.getTypePtr();
- return TypeNode != nullptr &&
- InnerMatcher.matches(*TypeNode, Finder, Builder);
+ if (CheckSugaredTypes && TypeNode != nullptr) {
+ TypeNode = TypeNode->getUnqualifiedDesugaredType();
+ }
+ return TypeNode != nullptr && arrayType().matches(*TypeNode, Finder, Builder);
}
AST_MATCHER(clang::RecordDecl, isExternCContext) {
@@ -43,7 +43,8 @@ AST_MATCHER(clang::ParmVarDecl, isArgvOfMain) {
AvoidCArraysCheck::AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
- AllowStringArrays(Options.get("AllowStringArrays", false)) {}
+ AllowStringArrays(Options.get("AllowStringArrays", false)),
+ CheckSugaredTypes(Options.get("CheckSugaredTypes", false)) {}
void AvoidCArraysCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "AllowStringArrays", AllowStringArrays);
@@ -60,7 +61,7 @@ void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) {
unless(parmVarDecl())))));
Finder->addMatcher(
- typeLoc(hasValidBeginLoc(), hasType(arrayType()),
+ typeLoc(hasValidBeginLoc(), hasArrayType(CheckSugaredTypes()),
optionally(hasParent(parmVarDecl().bind("param_decl"))),
unless(anyOf(hasParent(parmVarDecl(isArgvOfMain())),
hasParent(varDecl(isExternC())),
@@ -96,6 +97,26 @@ void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) {
diag(ArrayType->getBeginLoc(),
"do not declare %select{C-style|C VLA}0 arrays, use %1 instead")
<< IsVLA << llvm::join(RecommendTypes, " or ");
+
+ if (CheckSugaredTypes) {
+ PrintingPolicy PrintPolicy{getLangOpts()};
+ PrintPolicy.SuppressTagKeyword = true;
+
+ const auto TypeName = ArrayType->getType().getAsString(PrintPolicy);
+ const auto DesugaredTypeName = ArrayType->getType()
+ ->getUnqualifiedDesugaredType()
+ ->getCanonicalTypeInternal()
+ .getAsString(PrintPolicy);
+ if (TypeName != DesugaredTypeName) {
+ diag(ArrayType->getBeginLoc(), "declared type '%0' resolves to '%1'",
+ DiagnosticIDs::Note)
+ << TypeName << DesugaredTypeName;
+ } else {
+ diag(ArrayType->getBeginLoc(), "array type '%0' here",
+ DiagnosticIDs::Note)
+ << TypeName;
+ }
+ }
}
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.h b/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.h
index 719e88e4b3166..a22d656a78f33 100644
--- a/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/AvoidCArraysCheck.h
@@ -32,6 +32,7 @@ class AvoidCArraysCheck : public ClangTidyCheck {
private:
const bool AllowStringArrays;
+ const bool CheckSugaredTypes;
};
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-c-arrays.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-c-arrays.rst
index 6a386ecd0fd4b..78e3ef5f6fb13 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-c-arrays.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-c-arrays.rst
@@ -72,3 +72,9 @@ can be either ``char* argv[]`` or ``char** argv``, but cannot be
.. code:: c++
const char name[] = "Some name";
+
+.. option:: CheckSugaredTypes
+
+ When set to `true` (default is `false`), type aliases, decltypes as well as
+ template parameter types will get resolved and diagnosed as usage of
+ an array in case their underlying type resolves to an array type.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-check-sugared-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-check-sugared-types.cpp
new file mode 100644
index 0000000000000..1e1bcda885b21
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-check-sugared-types.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy -std=c++17 %s modernize-avoid-c-arrays %t -- \
+// RUN: -config='{CheckOptions: { modernize-avoid-c-arrays.CheckSugaredTypes: true }}'
+
+int a[] = {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+int b[1];
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+void foo() {
+ int c[b[0]];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C VLA arrays, use std::vector<> instead
+
+ using d = decltype(c);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not declare C VLA arrays, use std::vector<> instead
+ // CHECK-MESSAGES: :[[@LINE-2]]:13: note: declared type 'decltype(c)' resolves to 'int[b[0]]'
+
+ d e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C VLA arrays, use std::vector<> instead
+}
+
+template <typename T, int Size>
+class array {
+ T d[Size];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+
+ int e[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+};
+
+array<int[4], 2> d;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead
+
+using k = int[4];
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not declare C-style arrays, use std::array<> instead
+
+array<k, 2> dk;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead
+// CHECK-MESSAGES: :[[@LINE-2]]:7: note: declared type 'k' resolves to 'int[4]'
+
+template <typename T>
+class unique_ptr {
+ T *d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: note: array type 'int[]' here
+
+ int e[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+};
+
+unique_ptr<int[]> d2;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use std::array<> instead
+
+using k2 = int[];
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use std::array<> instead
+
+unique_ptr<k2> dk2;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use std::array<> instead
+// CHECK-MESSAGES: :[[@LINE-2]]:12: note: declared type 'k2' resolves to 'int[]'
+
+// Some header
+extern "C" {
+
+int f[] = {1, 2};
+
+int j[1];
+
+inline void bar() {
+ {
+ int j[j[0]];
+ }
+}
+
+extern "C++" {
+int f3[] = {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+int j3[1];
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+struct Foo {
+ int f3[3] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+
+ int j3[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+};
+}
+
+struct Bar {
+
+ int f[3] = {1, 2};
+
+ int j[1];
+};
+}
+
+const char name[] = "Some string";
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+
+void takeCharArray(const char name[]);
+// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+
+using MyIntArray = int[10];
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+
+using MyIntArray2D = MyIntArray[10];
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+// CHECK-MESSAGES: :[[@LINE-2]]:22: note: declared type 'MyIntArray[10]' resolves to 'int[10][10]'
+
+using MyIntArray3D = MyIntArray2D[10];
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+// CHECK-MESSAGES: :[[@LINE-2]]:22: note: declared type 'MyIntArray2D[10]' resolves to 'int[10][10][10]'
+
+MyIntArray3D array3D;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+// CHECK-MESSAGES: :[[@LINE-2]]:1: note: declared type 'MyIntArray3D' resolves to 'int[10][10][10]'
+
+MyIntArray2D array2D;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+// CHECK-MESSAGES: :[[@LINE-2]]:1: note: declared type 'MyIntArray2D' resolves to 'int[10][10]'
+
+MyIntArray array1D;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead [modernize-avoid-c-arrays]
+// CHECK-MESSAGES: :[[@LINE-2]]:1: note: declared type 'MyIntArray' resolves to 'int[10]'
More information about the cfe-commits
mailing list