diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h @@ -77,6 +77,7 @@ std::unique_ptr TUInfo; const unsigned long long MaxCopySize; const Confidence::Level MinConfidence; + const unsigned int AutoTypeNameLength; const VariableNamer::NamingStyle NamingStyle; utils::IncludeInserter Inserter; bool UseReverseRanges; diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -461,6 +461,7 @@ : ClangTidyCheck(Name, Context), TUInfo(new TUTrackingInfo), MaxCopySize(Options.get("MaxCopySize", 16ULL)), MinConfidence(Options.get("MinConfidence", Confidence::CL_Reasonable)), + AutoTypeNameLength(Options.get("AutoTypeNameLength", 0)), NamingStyle(Options.get("NamingStyle", VariableNamer::NS_CamelCase)), Inserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM)), @@ -484,6 +485,7 @@ void LoopConvertCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "MaxCopySize", MaxCopySize); Options.store(Opts, "MinConfidence", MinConfidence); + Options.store(Opts, "AutoTypeNameLength", AutoTypeNameLength); Options.store(Opts, "NamingStyle", NamingStyle); Options.store(Opts, "IncludeStyle", Inserter.getStyle()); Options.store(Opts, "UseCxx20ReverseRanges", UseCxx20IfAvailable); @@ -627,8 +629,12 @@ SourceRange ParenRange(Loop->getLParenLoc(), Loop->getRParenLoc()); QualType Type = Context->getAutoDeductType(); - if (!Descriptor.ElemType.isNull() && Descriptor.ElemType->isFundamentalType()) - Type = Descriptor.ElemType.getUnqualifiedType(); + if (!Descriptor.ElemType.isNull()) { + auto FullType = Descriptor.ElemType.getUnqualifiedType(); + if (Descriptor.ElemType->isFundamentalType() || + FullType.getAsString(getLangOpts()).length() <= AutoTypeNameLength) + Type = FullType; + } Type = Type.getDesugaredType(*Context); // If the new variable name is from the aliased variable, then the reference diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst --- a/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst @@ -121,23 +121,23 @@ Reverse Iterator Support ------------------------ -The converter is also capable of transforming iterator loops which use -``rbegin`` and ``rend`` for looping backwards over a container. Out of the box -this will automatically happen in C++20 mode using the ``ranges`` library, -however the check can be configured to work without C++20 by specifying a +The converter is also capable of transforming iterator loops which use +``rbegin`` and ``rend`` for looping backwards over a container. Out of the box +this will automatically happen in C++20 mode using the ``ranges`` library, +however the check can be configured to work without C++20 by specifying a function to reverse a range and optionally the header file where that function lives. .. option:: UseCxx20ReverseRanges - - When set to true convert loops when in C++20 or later mode using + + When set to true convert loops when in C++20 or later mode using ``std::ranges::reverse_view``. Default value is ``true``. .. option:: MakeReverseRangeFunction - Specify the function used to reverse an iterator pair, the function should - accept a class with ``rbegin`` and ``rend`` methods and return a + Specify the function used to reverse an iterator pair, the function should + accept a class with ``rbegin`` and ``rend`` methods and return a class with ``begin`` and ``end`` methods methods that call the ``rbegin`` and ``rend`` methods respectively. Common examples are ``ranges::reverse_view`` and ``llvm::reverse``. @@ -146,10 +146,10 @@ .. option:: MakeReverseRangeHeader Specifies the header file where :option:`MakeReverseRangeFunction` is - declared. For the previous examples this option would be set to + declared. For the previous examples this option would be set to ``range/v3/view/reverse.hpp`` and ``llvm/ADT/STLExtras.h`` respectively. - If this is an empty string and :option:`MakeReverseRangeFunction` is set, - the check will proceed on the assumption that the function is already + If this is an empty string and :option:`MakeReverseRangeFunction` is set, + the check will proceed on the assumption that the function is already available in the translation unit. This can be wrapped in angle brackets to signify to add the include as a system include. @@ -160,6 +160,13 @@ A string specifying which include-style is used, `llvm` or `google`. Default is `llvm`. +AutoTypeNameLength option +------------------------ + +If TypeName length is strictly above this threshold, `auto` will be used. + +The default is 0, so `auto` will be used for all types except C++ fundamental types. + Limitations ----------- diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-auto.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-auto.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \ +// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.AutoTypeNameLength, value: '22'}]}" \ +// RUN: -- -I %S/Inputs/modernize-loop-convert + +#include "structures.h" + +const int N = 6; + +void autotype() { + Val Teas[N]; + for (int I = 0; I < N; ++I) { + Teas[I].g(); + } + // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (Val & Tea : Teas) + // CHECK-FIXES-NEXT: Tea.g(); + + // NonTriviallyCopyable has length 21 < 22 + const NonTriviallyCopyable NonCopy[N]{}; + for (int I = 0; I < N; ++I) { + printf("2 * %d = %d\n", NonCopy[I].X, NonCopy[I].X + NonCopy[I].X); + } + // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (const NonTriviallyCopyable & I : NonCopy) + // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I.X, I.X + I.X); + + // TriviallyCopyableButBig has length 23 > 22 + const TriviallyCopyableButBig Big[N]{}; + for (int I = 0; I < N; ++I) { + printf("2 * %d = %d\n", Big[I].X, Big[I].X + Big[I].X); + } + // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (const auto & I : Big) + // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I.X, I.X + I.X); +}