https://github.com/stmuench updated https://github.com/llvm/llvm-project/pull/131468
>From b5457130eb02f32e83416747b770b281b477d5cd Mon Sep 17 00:00:00 2001 From: stmuench <stmue...@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 | 126 ++++++++++++++++++ 4 files changed, 161 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..5a2997e19bdc2 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..abd3037f18f05 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 + C-style array in case their underlying type resolves to one. 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..e0de4ee811712 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-arrays-check-sugared-types.cpp @@ -0,0 +1,126 @@ +// 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 + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: declared type 'd' resolves to 'int[b[0]]' +} + +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' or 'std::vector' 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]' _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits