njames93 updated this revision to Diff 282757.
njames93 added a comment.
- Rebased trunk
- Cleaned up test cases
- Added support for specifying to include as system include.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D82089/new/
https://reviews.llvm.org/D82089
Files:
clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h
clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst
clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-reverse.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-reverse.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-reverse.cpp
@@ -0,0 +1,115 @@
+// RUN: %check_clang_tidy -std=c++20 -check-suffixes=,RANGES %s modernize-loop-convert %t
+
+// RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-SYS %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [ \
+// RUN: {key: modernize-loop-convert.MakeReverseRangeFunction, value: 'llvm::reverse'}, \
+// RUN: {key: modernize-loop-convert.MakeReverseRangeHeader, value: 'llvm/ADT/STLExtras.h'}]}"
+
+// RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-SYS %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [ \
+// RUN: {key: modernize-loop-convert.MakeReverseRangeFunction, value: 'llvm::reverse'}, \
+// RUN: {key: modernize-loop-convert.MakeReverseRangeHeader, value: '<llvm/ADT/STLExtras.h>'}]}"
+
+// RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-HEADER %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [ \
+// RUN: {key: modernize-loop-convert.MakeReverseRangeFunction, value: 'llvm::reverse'}]}"
+
+// Ensure the check doesn't transform reverse loops when not in c++20 mode or
+// when UseCxx20ReverseRanges has been disabled
+// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -- -std=c++17 | count 0
+
+// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: \
+// RUN: [{key: modernize-loop-convert.UseCxx20ReverseRanges, value: 'false'}] \
+// RUN: }" -- -std=c++20 | count 0
+
+// Ensure we get a warning if we supply the header argument without the
+// function argument.
+// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: [ \
+// RUN: {key: modernize-loop-convert.MakeReverseRangeHeader, value: 'llvm/ADT/STLExtras.h'}]}" \
+// RUN: -- -std=c++17 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-HEADER-NO-FUNC \
+// RUN: -implicit-check-not="{{warning|error}}:"
+
+// CHECK-HEADER-NO-FUNC: warning: modernize-loop-convert: 'MakeReverseRangeHeader' is set but 'MakeReverseRangeFunction' is not, disabling reverse loop transformation
+
+// Make sure appropiate headers are included
+// CHECK-FIXES-RANGES: #include <ranges>
+// CHECK-FIXES-CUSTOM-NO-SYS: #include "llvm/ADT/STLExtras.h"
+// CHECK-FIXES-CUSTOM-SYS: #include <llvm/ADT/STLExtras.h>
+
+// Make sure no header is included in this example
+// CHECK-FIXES-CUSTOM-NO-HEADER-NOT: #include
+
+template <typename T>
+struct Reversable {
+ using iterator = T *;
+ using const_iterator = const T *;
+
+ iterator begin();
+ iterator end();
+ iterator rbegin();
+ iterator rend();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+ const_iterator rbegin() const;
+ const_iterator rend() const;
+
+ const_iterator cbegin() const;
+ const_iterator cend() const;
+ const_iterator crbegin() const;
+ const_iterator crend() const;
+};
+
+template <typename T>
+void observe(const T &);
+template <typename T>
+void mutate(T &);
+
+void constContainer(const Reversable<int> &Numbers) {
+ for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) {
+ observe(*I);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
+ // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
+ // CHECK-FIXES-NEXT: observe(Number);
+ // CHECK-FIXES-NEXT: }
+
+ for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) {
+ observe(*I);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
+ // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
+ // CHECK-FIXES-NEXT: observe(Number);
+ // CHECK-FIXES-NEXT: }
+
+ // Ensure these bad loops aren't transformed.
+ for (auto I = Numbers.rbegin(), E = Numbers.end(); I != E; ++I) {
+ observe(*I);
+ }
+ for (auto I = Numbers.begin(), E = Numbers.rend(); I != E; ++I) {
+ observe(*I);
+ }
+}
+
+void nonConstContainer(Reversable<int> &Numbers) {
+ for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) {
+ mutate(*I);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) {
+ // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) {
+ // CHECK-FIXES-NEXT: mutate(Number);
+ // CHECK-FIXES-NEXT: }
+
+ for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) {
+ observe(*I);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
+ // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
+ // CHECK-FIXES-NEXT: observe(Number);
+ // CHECK-FIXES-NEXT: }
+}
Index: clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst
@@ -118,6 +118,48 @@
for (auto & elem : v)
cout << elem;
+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
+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
+ ``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
+ class with ``begin`` and ``end`` methods methods that call the ``rbegin`` and
+ ``rend`` methods respectively. Common examples are ``ranges::reverse_view``
+ and ``llvm::reverse``.
+ Default value is an empty string.
+
+.. option:: MakeReverseRangeHeader
+
+ Specifies the header file where :option:`MakeReverseRangeFunction` is
+ 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
+ available in the translation unit.
+ This can be wrapped in angle brackets to signify to add the include as a
+ system include.
+ Default value is an empty string.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
+
Limitations
-----------
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -70,6 +70,11 @@
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Improved :doc:`modernize-loop-convert
+ <clang-tidy/checks/modernize-loop-convert>` check.
+
+ Now able to transform iterator loops using ``rbegin`` and ``rend`` methods.
+
- Improved :doc:`readability-identifier-naming
<clang-tidy/checks/readability-identifier-naming>` check.
Index: clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h
===================================================================
--- clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h
+++ clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h
@@ -26,7 +26,12 @@
namespace tidy {
namespace modernize {
-enum LoopFixerKind { LFK_Array, LFK_Iterator, LFK_PseudoArray };
+enum LoopFixerKind {
+ LFK_Array,
+ LFK_Iterator,
+ LFK_ReverseIterator,
+ LFK_PseudoArray
+};
/// A map used to walk the AST in reverse: maps child Stmt to parent Stmt.
typedef llvm::DenseMap<const clang::Stmt *, const clang::Stmt *> StmtParentMap;
Index: clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h
+++ clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_H
#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
#include "LoopConvertUtils.h"
namespace clang {
@@ -24,6 +25,8 @@
}
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
private:
@@ -34,6 +37,29 @@
bool DerefByValue;
std::string ContainerString;
QualType ElemType;
+ bool NeedsReverseCall;
+ };
+
+ class ReverseRangeDetail {
+ public:
+ ReverseRangeDetail(bool UseCxx20IfAvailable, std::string FunctionName,
+ std::string HeaderName, const LangOptions &LangOpts);
+
+ bool isEnabled() const { return IsEnabled; }
+ bool shouldIncludeHeader() const {
+ return isEnabled() && !getHeader().empty();
+ }
+ bool isUsingCxx20() const { return UseCxx20IfAvailable; }
+ bool isSystemInclude() const { return IsSystemInclude; }
+ StringRef getFunction() const { return Function; }
+ StringRef getHeader() const { return Header; }
+
+ private:
+ bool IsEnabled{false};
+ bool UseCxx20IfAvailable;
+ bool IsSystemInclude;
+ std::string Function;
+ std::string Header;
};
void getAliasRange(SourceManager &SM, SourceRange &DeclRange);
@@ -71,6 +97,8 @@
const unsigned long long MaxCopySize;
const Confidence::Level MinConfidence;
const VariableNamer::NamingStyle NamingStyle;
+ utils::IncludeInserter Inserter;
+ const ReverseRangeDetail ReverseRange;
};
} // namespace modernize
Index: clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -19,6 +19,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstring>
#include <utility>
@@ -57,6 +59,7 @@
static const char LoopNameArray[] = "forLoopArray";
static const char LoopNameIterator[] = "forLoopIterator";
+static const char LoopNameReverseIterator[] = "forLoopReverseIterator";
static const char LoopNamePseudoArray[] = "forLoopPseudoArray";
static const char ConditionBoundName[] = "conditionBound";
static const char ConditionVarName[] = "conditionVar";
@@ -68,7 +71,9 @@
static const char EndVarName[] = "endVar";
static const char DerefByValueResultName[] = "derefByValueResult";
static const char DerefByRefResultName[] = "derefByRefResult";
-
+static const char MakeReverseRangeFunction[] = "MakeReverseRangeFunction";
+static const char MakeReverseRangeHeader[] = "MakeReverseRangeHeader";
+static const char UseCxx20ReverseRanges[] = "UseCxx20ReverseRanges";
// shared matchers
static const TypeMatcher AnyType() { return anything(); }
@@ -150,10 +155,17 @@
/// - The iterator variables 'it', 'f', and 'h' are the same.
/// - The two containers on which 'begin' and 'end' are called are the same.
/// - If the end iterator variable 'g' is defined, it is the same as 'f'.
-StatementMatcher makeIteratorLoopMatcher() {
+StatementMatcher makeIteratorLoopMatcher(bool IsReverse) {
+
+ auto BeginNameMatcher = IsReverse ? hasAnyName("rbegin", "crbegin")
+ : hasAnyName("begin", "cbegin");
+
+ auto EndNameMatcher =
+ IsReverse ? hasAnyName("rend", "crend") : hasAnyName("end", "cend");
+
StatementMatcher BeginCallMatcher =
cxxMemberCallExpr(argumentCountIs(0),
- callee(cxxMethodDecl(hasAnyName("begin", "cbegin"))))
+ callee(cxxMethodDecl(BeginNameMatcher)))
.bind(BeginCallName);
DeclarationMatcher InitDeclMatcher =
@@ -167,7 +179,7 @@
varDecl(hasInitializer(anything())).bind(EndVarName);
StatementMatcher EndCallMatcher = cxxMemberCallExpr(
- argumentCountIs(0), callee(cxxMethodDecl(hasAnyName("end", "cend"))));
+ argumentCountIs(0), callee(cxxMethodDecl(EndNameMatcher)));
StatementMatcher IteratorBoundMatcher =
expr(anyOf(ignoringParenImpCasts(
@@ -225,7 +237,7 @@
hasArgument(
0, declRefExpr(to(varDecl(TestDerefReturnsByValue)
.bind(IncrementVarName))))))))
- .bind(LoopNameIterator);
+ .bind(IsReverse ? LoopNameReverseIterator : LoopNameIterator);
}
/// The matcher used for array-like containers (pseudoarrays).
@@ -325,7 +337,7 @@
/// the output parameter isArrow is set to indicate whether the initialization
/// is called via . or ->.
static const Expr *getContainerFromBeginEndCall(const Expr *Init, bool IsBegin,
- bool *IsArrow) {
+ bool *IsArrow, bool IsReverse) {
// FIXME: Maybe allow declaration/initialization outside of the for loop.
const auto *TheCall =
dyn_cast_or_null<CXXMemberCallExpr>(digThroughConstructors(Init));
@@ -336,9 +348,11 @@
if (!Member)
return nullptr;
StringRef Name = Member->getMemberDecl()->getName();
- StringRef TargetName = IsBegin ? "begin" : "end";
- StringRef ConstTargetName = IsBegin ? "cbegin" : "cend";
- if (Name != TargetName && Name != ConstTargetName)
+ if (!Name.consume_back(IsBegin ? "begin" : "end"))
+ return nullptr;
+ if (IsReverse && !Name.consume_back("r"))
+ return nullptr;
+ if (!Name.empty() && !Name.equals("c"))
return nullptr;
const Expr *SourceExpr = Member->getBase();
@@ -356,18 +370,19 @@
/// must be a member.
static const Expr *findContainer(ASTContext *Context, const Expr *BeginExpr,
const Expr *EndExpr,
- bool *ContainerNeedsDereference) {
+ bool *ContainerNeedsDereference,
+ bool IsReverse) {
// Now that we know the loop variable and test expression, make sure they are
// valid.
bool BeginIsArrow = false;
bool EndIsArrow = false;
- const Expr *BeginContainerExpr =
- getContainerFromBeginEndCall(BeginExpr, /*IsBegin=*/true, &BeginIsArrow);
+ const Expr *BeginContainerExpr = getContainerFromBeginEndCall(
+ BeginExpr, /*IsBegin=*/true, &BeginIsArrow, IsReverse);
if (!BeginContainerExpr)
return nullptr;
- const Expr *EndContainerExpr =
- getContainerFromBeginEndCall(EndExpr, /*IsBegin=*/false, &EndIsArrow);
+ const Expr *EndContainerExpr = getContainerFromBeginEndCall(
+ EndExpr, /*IsBegin=*/false, &EndIsArrow, IsReverse);
// Disallow loops that try evil things like this (note the dot and arrow):
// for (IteratorType It = Obj.begin(), E = Obj->end(); It != E; ++It) { }
if (!EndContainerExpr || BeginIsArrow != EndIsArrow ||
@@ -475,27 +490,49 @@
LoopConvertCheck::RangeDescriptor::RangeDescriptor()
: ContainerNeedsDereference(false), DerefByConstRef(false),
- DerefByValue(false) {}
+ DerefByValue(false), NeedsReverseCall(false) {}
+
+static constexpr StringRef RangesMakeReverse = "std::ranges::reverse_view";
+static constexpr StringRef RangesMakeReverseHeader = "ranges";
LoopConvertCheck::LoopConvertCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), TUInfo(new TUTrackingInfo),
MaxCopySize(Options.get("MaxCopySize", 16ULL)),
MinConfidence(Options.get("MinConfidence", Confidence::CL_Reasonable)),
- NamingStyle(Options.get("NamingStyle", VariableNamer::NS_CamelCase)) {}
+ NamingStyle(Options.get("NamingStyle", VariableNamer::NS_CamelCase)),
+ Inserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM)),
+ ReverseRange(Options.get(UseCxx20ReverseRanges, true),
+ Options.get(MakeReverseRangeFunction, ""),
+ Options.get(MakeReverseRangeHeader, ""), getLangOpts()) {}
void LoopConvertCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
- Options.store(Opts, "MaxCopySize", std::to_string(MaxCopySize));
+ Options.store(Opts, "MaxCopySize", MaxCopySize);
Options.store(Opts, "MinConfidence", MinConfidence);
Options.store(Opts, "NamingStyle", NamingStyle);
+ Options.store(Opts, "IncludeStyle", Inserter.getStyle());
+ Options.store(Opts, UseCxx20ReverseRanges, ReverseRange.isUsingCxx20());
+ Options.store(Opts, MakeReverseRangeFunction, ReverseRange.getFunction());
+ Options.store(Opts, MakeReverseRangeHeader, ReverseRange.getHeader());
+}
+
+void LoopConvertCheck::registerPPCallbacks(const SourceManager &SM,
+ Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) {
+ Inserter.registerPreprocessor(PP);
}
void LoopConvertCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, makeArrayLoopMatcher()),
this);
Finder->addMatcher(
- traverse(ast_type_traits::TK_AsIs, makeIteratorLoopMatcher()), this);
+ traverse(ast_type_traits::TK_AsIs, makeIteratorLoopMatcher(false)), this);
Finder->addMatcher(
traverse(ast_type_traits::TK_AsIs, makePseudoArrayLoopMatcher()), this);
+ if (ReverseRange.isEnabled())
+ Finder->addMatcher(
+ traverse(ast_type_traits::TK_AsIs, makeIteratorLoopMatcher(true)),
+ this);
}
/// Given the range of a single declaration, such as:
@@ -646,13 +683,29 @@
}
}
- StringRef MaybeDereference = Descriptor.ContainerNeedsDereference ? "*" : "";
- std::string TypeString = Type.getAsString(getLangOpts());
- std::string Range = ("(" + TypeString + " " + VarName + " : " +
- MaybeDereference + Descriptor.ContainerString + ")")
- .str();
+ SmallString<128> Range;
+ llvm::raw_svector_ostream Output(Range);
+ Output << '(';
+ Type.print(Output, getLangOpts());
+ Output << ' ' << VarName << " : ";
+ if (Descriptor.NeedsReverseCall)
+ Output << ReverseRange.getFunction() << '(';
+ if (Descriptor.ContainerNeedsDereference)
+ Output << '*';
+ Output << Descriptor.ContainerString;
+ if (Descriptor.NeedsReverseCall)
+ Output << "))";
+ else
+ Output << ')';
FixIts.push_back(FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(ParenRange), Range));
+
+ if (Descriptor.NeedsReverseCall && ReverseRange.shouldIncludeHeader()) {
+ if (Optional<FixItHint> Insertion = Inserter.createIncludeInsertion(
+ Context->getSourceManager().getFileID(Loop->getBeginLoc()),
+ ReverseRange.getHeader(), ReverseRange.isSystemInclude()))
+ FixIts.push_back(*Insertion);
+ }
diag(Loop->getForLoc(), "use range-based for loop instead") << FixIts;
TUInfo->getGeneratedDecls().insert(make_pair(Loop, VarName));
}
@@ -762,8 +815,9 @@
const UsageResult &Usages, RangeDescriptor &Descriptor) {
Descriptor.ContainerString =
std::string(getContainerString(Context, Loop, ContainerExpr));
+ Descriptor.NeedsReverseCall = (FixerKind == LFK_ReverseIterator);
- if (FixerKind == LFK_Iterator)
+ if (FixerKind == LFK_Iterator || FixerKind == LFK_ReverseIterator)
getIteratorLoopQualifiers(Context, Nodes, Descriptor);
else
getArrayLoopQualifiers(Context, Nodes, ContainerExpr, Usages, Descriptor);
@@ -792,7 +846,7 @@
return false;
// FIXME: Try to put most of this logic inside a matcher.
- if (FixerKind == LFK_Iterator) {
+ if (FixerKind == LFK_Iterator || FixerKind == LFK_ReverseIterator) {
QualType InitVarType = InitVar->getType();
QualType CanonicalInitVarType = InitVarType.getCanonicalType();
@@ -831,6 +885,8 @@
FixerKind = LFK_Array;
} else if ((Loop = Nodes.getNodeAs<ForStmt>(LoopNameIterator))) {
FixerKind = LFK_Iterator;
+ } else if ((Loop = Nodes.getNodeAs<ForStmt>(LoopNameReverseIterator))) {
+ FixerKind = LFK_ReverseIterator;
} else {
Loop = Nodes.getNodeAs<ForStmt>(LoopNamePseudoArray);
assert(Loop && "Bad Callback. No for statement");
@@ -858,10 +914,11 @@
// With array loops, the container is often discovered during the
// ForLoopIndexUseVisitor traversal.
const Expr *ContainerExpr = nullptr;
- if (FixerKind == LFK_Iterator) {
- ContainerExpr = findContainer(Context, LoopVar->getInit(),
- EndVar ? EndVar->getInit() : EndCall,
- &Descriptor.ContainerNeedsDereference);
+ if (FixerKind == LFK_Iterator || FixerKind == LFK_ReverseIterator) {
+ ContainerExpr = findContainer(
+ Context, LoopVar->getInit(), EndVar ? EndVar->getInit() : EndCall,
+ &Descriptor.ContainerNeedsDereference,
+ /*IsReverse*/ FixerKind == LFK_ReverseIterator);
} else if (FixerKind == LFK_PseudoArray) {
ContainerExpr = EndCall->getImplicitObjectArgument();
Descriptor.ContainerNeedsDereference =
@@ -927,6 +984,38 @@
Finder.aliasFromForInit(), Loop, Descriptor);
}
+LoopConvertCheck::ReverseRangeDetail::ReverseRangeDetail(
+ bool UseCxx20IfAvailable, std::string FunctionName, std::string HeaderName,
+ const LangOptions &LangOpts)
+ : UseCxx20IfAvailable(UseCxx20IfAvailable), IsSystemInclude(false),
+ Function(std::move(FunctionName)), Header(std::move(HeaderName)) {
+ if (Function.empty() && !Header.empty()) {
+ llvm::WithColor::warning()
+ << "modernize-loop-convert: '" << MakeReverseRangeHeader
+ << "' is set but '" << MakeReverseRangeFunction
+ << "' is not, disabling reverse loop transformation\n";
+ IsEnabled = false;
+ return;
+ }
+ if (Function.empty()) {
+ if (UseCxx20IfAvailable && LangOpts.CPlusPlus20) {
+ IsEnabled = true;
+ Function = RangesMakeReverse.str();
+ Header = RangesMakeReverseHeader.str();
+ IsSystemInclude = true;
+ } else {
+ IsEnabled = false;
+ }
+ return;
+ }
+ if (Header.front() == '<' && Header.back() == '>') {
+ IsSystemInclude = true;
+ Header.pop_back();
+ Header.erase(0, 1);
+ }
+ IsEnabled = true;
+}
+
} // namespace modernize
} // namespace tidy
} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits