1 //===--- LoopConvertUtils.cpp - clang-tidy --------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "LoopConvertUtils.h"
10 #include "../utils/ASTUtils.h"
11 #include "clang/Basic/IdentifierTable.h"
12 #include "clang/Basic/LLVM.h"
13 #include "clang/Basic/Lambda.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Basic/TokenKinds.h"
17 #include "clang/Lex/Lexer.h"
18 #include "llvm/ADT/APSInt.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/Casting.h"
29 using namespace clang::ast_matchers
;
31 namespace clang::tidy::modernize
{
33 /// Tracks a stack of parent statements during traversal.
35 /// All this really does is inject push_back() before running
36 /// RecursiveASTVisitor::TraverseStmt() and pop_back() afterwards. The Stmt atop
37 /// the stack is the parent of the current statement (NULL for the topmost
39 bool StmtAncestorASTVisitor::TraverseStmt(Stmt
*Statement
) {
40 StmtAncestors
.insert(std::make_pair(Statement
, StmtStack
.back()));
41 StmtStack
.push_back(Statement
);
42 RecursiveASTVisitor
<StmtAncestorASTVisitor
>::TraverseStmt(Statement
);
47 /// Keep track of the DeclStmt associated with each VarDecl.
49 /// Combined with StmtAncestors, this provides roughly the same information as
50 /// Scope, as we can map a VarDecl to its DeclStmt, then walk up the parent tree
51 /// using StmtAncestors.
52 bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt
*Statement
) {
53 for (const auto *Decl
: Statement
->decls()) {
54 if (const auto *V
= dyn_cast
<VarDecl
>(Decl
))
55 DeclParents
.insert(std::make_pair(V
, Statement
));
60 /// record the DeclRefExpr as part of the parent expression.
61 bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr
*E
) {
62 Components
.push_back(E
);
66 /// record the MemberExpr as part of the parent expression.
67 bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr
*Member
) {
68 Components
.push_back(Member
);
72 /// Forward any DeclRefExprs to a check on the referenced variable
74 bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr
*DeclRef
) {
75 if (auto *V
= dyn_cast_or_null
<VarDecl
>(DeclRef
->getDecl()))
76 return VisitVarDecl(V
);
80 /// Determine if any this variable is declared inside the ContainingStmt.
81 bool DependencyFinderASTVisitor::VisitVarDecl(VarDecl
*V
) {
82 const Stmt
*Curr
= DeclParents
->lookup(V
);
83 // First, see if the variable was declared within an inner scope of the loop.
84 while (Curr
!= nullptr) {
85 if (Curr
== ContainingStmt
) {
86 DependsOnInsideVariable
= true;
89 Curr
= StmtParents
->lookup(Curr
);
92 // Next, check if the variable was removed from existence by an earlier
94 for (const auto &I
: *ReplacedVars
) {
96 DependsOnInsideVariable
= true;
103 /// If we already created a variable for TheLoop, check to make sure
104 /// that the name was not already taken.
105 bool DeclFinderASTVisitor::VisitForStmt(ForStmt
*TheLoop
) {
106 StmtGeneratedVarNameMap::const_iterator I
= GeneratedDecls
->find(TheLoop
);
107 if (I
!= GeneratedDecls
->end() && I
->second
== Name
) {
114 /// If any named declaration within the AST subtree has the same name,
115 /// then consider Name already taken.
116 bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl
*D
) {
117 const IdentifierInfo
*Ident
= D
->getIdentifier();
118 if (Ident
&& Ident
->getName() == Name
) {
125 /// Forward any declaration references to the actual check on the
126 /// referenced declaration.
127 bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr
*DeclRef
) {
128 if (auto *D
= dyn_cast
<NamedDecl
>(DeclRef
->getDecl()))
129 return VisitNamedDecl(D
);
133 /// If the new variable name conflicts with any type used in the loop,
134 /// then we mark that variable name as taken.
135 bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL
) {
136 QualType QType
= TL
.getType();
138 // Check if our name conflicts with a type, to handle for typedefs.
139 if (QType
.getAsString() == Name
) {
143 // Check for base type conflicts. For example, when a struct is being
144 // referenced in the body of the loop, the above getAsString() will return the
145 // whole type (ex. "struct s"), but will be caught here.
146 if (const IdentifierInfo
*Ident
= QType
.getBaseTypeIdentifier()) {
147 if (Ident
->getName() == Name
) {
155 /// Look through conversion/copy constructors and member functions to find the
156 /// explicit initialization expression, returning it is found.
158 /// The main idea is that given
160 /// we consider either of these initializations
161 /// vector<int>::iterator it = v.begin();
162 /// vector<int>::iterator it(v.begin());
163 /// vector<int>::const_iterator it(v.begin());
164 /// and retrieve `v.begin()` as the expression used to initialize `it` but do
166 /// vector<int>::iterator it;
167 /// vector<int>::iterator it(v.begin(), 0); // if this constructor existed
168 /// as being initialized from `v.begin()`
169 const Expr
*digThroughConstructorsConversions(const Expr
*E
) {
172 E
= E
->IgnoreImplicit();
173 if (const auto *ConstructExpr
= dyn_cast
<CXXConstructExpr
>(E
)) {
174 // The initial constructor must take exactly one parameter, but base class
175 // and deferred constructors can take more.
176 if (ConstructExpr
->getNumArgs() != 1 ||
177 ConstructExpr
->getConstructionKind() != CXXConstructExpr::CK_Complete
)
179 E
= ConstructExpr
->getArg(0);
180 if (const auto *Temp
= dyn_cast
<MaterializeTemporaryExpr
>(E
))
181 E
= Temp
->getSubExpr();
182 return digThroughConstructorsConversions(E
);
184 // If this is a conversion (as iterators commonly convert into their const
185 // iterator counterparts), dig through that as well.
186 if (const auto *ME
= dyn_cast
<CXXMemberCallExpr
>(E
))
187 if (isa
<CXXConversionDecl
>(ME
->getMethodDecl()))
188 return digThroughConstructorsConversions(ME
->getImplicitObjectArgument());
192 /// Returns true when two Exprs are equivalent.
193 bool areSameExpr(ASTContext
*Context
, const Expr
*First
, const Expr
*Second
) {
194 return utils::areStatementsIdentical(First
, Second
, *Context
, true);
197 /// Returns the DeclRefExpr represented by E, or NULL if there isn't one.
198 const DeclRefExpr
*getDeclRef(const Expr
*E
) {
199 return dyn_cast
<DeclRefExpr
>(E
->IgnoreParenImpCasts());
202 /// Returns true when two ValueDecls are the same variable.
203 bool areSameVariable(const ValueDecl
*First
, const ValueDecl
*Second
) {
204 return First
&& Second
&&
205 First
->getCanonicalDecl() == Second
->getCanonicalDecl();
208 /// Determines if an expression is a declaration reference to a
209 /// particular variable.
210 static bool exprReferencesVariable(const ValueDecl
*Target
, const Expr
*E
) {
213 const DeclRefExpr
*Decl
= getDeclRef(E
);
214 return Decl
&& areSameVariable(Target
, Decl
->getDecl());
217 /// If the expression is a dereference or call to operator*(), return the
218 /// operand. Otherwise, return NULL.
219 static const Expr
*getDereferenceOperand(const Expr
*E
) {
220 if (const auto *Uop
= dyn_cast
<UnaryOperator
>(E
))
221 return Uop
->getOpcode() == UO_Deref
? Uop
->getSubExpr() : nullptr;
223 if (const auto *OpCall
= dyn_cast
<CXXOperatorCallExpr
>(E
)) {
224 return OpCall
->getOperator() == OO_Star
&& OpCall
->getNumArgs() == 1
232 /// Returns true when the Container contains an Expr equivalent to E.
233 template <typename ContainerT
>
234 static bool containsExpr(ASTContext
*Context
, const ContainerT
*Container
,
236 llvm::FoldingSetNodeID ID
;
237 E
->Profile(ID
, *Context
, true);
238 for (const auto &I
: *Container
) {
245 /// Returns true when the index expression is a declaration reference to
248 /// If the index variable is `index`, this function returns true on
249 /// arrayExpression[index];
250 /// containerExpression[index];
252 /// containerExpression[notIndex];
253 static bool isIndexInSubscriptExpr(const Expr
*IndexExpr
,
254 const VarDecl
*IndexVar
) {
255 const DeclRefExpr
*Idx
= getDeclRef(IndexExpr
);
256 return Idx
&& Idx
->getType()->isIntegerType() &&
257 areSameVariable(IndexVar
, Idx
->getDecl());
260 /// Returns true when the index expression is a declaration reference to
261 /// IndexVar, Obj is the same expression as SourceExpr after all parens and
262 /// implicit casts are stripped off.
264 /// If PermitDeref is true, IndexExpression may
265 /// be a dereference (overloaded or builtin operator*).
267 /// This function is intended for array-like containers, as it makes sure that
268 /// both the container and the index match.
269 /// If the loop has index variable `index` and iterates over `container`, then
270 /// isIndexInSubscriptExpr returns true for
273 /// container.at(index)
274 /// container->at(index)
278 /// container[notIndex]
279 /// notContainer[index]
281 /// If PermitDeref is true, then isIndexInSubscriptExpr additionally returns
282 /// true on these expressions:
284 /// (*container)[index]
285 /// (*container).at(index)
287 static bool isIndexInSubscriptExpr(ASTContext
*Context
, const Expr
*IndexExpr
,
288 const VarDecl
*IndexVar
, const Expr
*Obj
,
289 const Expr
*SourceExpr
, bool PermitDeref
) {
290 if (!SourceExpr
|| !Obj
|| !isIndexInSubscriptExpr(IndexExpr
, IndexVar
))
293 if (areSameExpr(Context
, SourceExpr
->IgnoreParenImpCasts(),
294 Obj
->IgnoreParenImpCasts()))
297 if (const Expr
*InnerObj
= getDereferenceOperand(Obj
->IgnoreParenImpCasts()))
298 if (PermitDeref
&& areSameExpr(Context
, SourceExpr
->IgnoreParenImpCasts(),
299 InnerObj
->IgnoreParenImpCasts()))
305 /// Returns true when Opcall is a call a one-parameter dereference of
308 /// For example, if the index variable is `index`, returns true for
313 static bool isDereferenceOfOpCall(const CXXOperatorCallExpr
*OpCall
,
314 const VarDecl
*IndexVar
) {
315 return OpCall
->getOperator() == OO_Star
&& OpCall
->getNumArgs() == 1 &&
316 exprReferencesVariable(IndexVar
, OpCall
->getArg(0));
319 /// Returns true when Uop is a dereference of IndexVar.
321 /// For example, if the index variable is `index`, returns true for
326 static bool isDereferenceOfUop(const UnaryOperator
*Uop
,
327 const VarDecl
*IndexVar
) {
328 return Uop
->getOpcode() == UO_Deref
&&
329 exprReferencesVariable(IndexVar
, Uop
->getSubExpr());
332 /// Determines whether the given Decl defines a variable initialized to
335 /// This is intended to find cases such as
337 /// for (int i = 0; i < arraySize(arr); ++i) {
339 /// // use t, do not use i
344 /// for (iterator i = container.begin(), e = container.end(); i != e; ++i) {
346 /// // use t, do not use i
349 static bool isAliasDecl(ASTContext
*Context
, const Decl
*TheDecl
,
350 const VarDecl
*IndexVar
) {
351 const auto *VDecl
= dyn_cast
<VarDecl
>(TheDecl
);
354 if (!VDecl
->hasInit())
357 bool OnlyCasts
= true;
358 const Expr
*Init
= VDecl
->getInit()->IgnoreParenImpCasts();
359 if (isa_and_nonnull
<CXXConstructExpr
>(Init
)) {
360 Init
= digThroughConstructorsConversions(Init
);
366 // Check that the declared type is the same as (or a reference to) the
369 QualType InitType
= Init
->getType();
370 QualType DeclarationType
= VDecl
->getType();
371 if (!DeclarationType
.isNull() && DeclarationType
->isReferenceType())
372 DeclarationType
= DeclarationType
.getNonReferenceType();
374 if (InitType
.isNull() || DeclarationType
.isNull() ||
375 !Context
->hasSameUnqualifiedType(DeclarationType
, InitType
))
379 switch (Init
->getStmtClass()) {
380 case Stmt::ArraySubscriptExprClass
: {
381 const auto *E
= cast
<ArraySubscriptExpr
>(Init
);
382 // We don't really care which array is used here. We check to make sure
383 // it was the correct one later, since the AST will traverse it next.
384 return isIndexInSubscriptExpr(E
->getIdx(), IndexVar
);
387 case Stmt::UnaryOperatorClass
:
388 return isDereferenceOfUop(cast
<UnaryOperator
>(Init
), IndexVar
);
390 case Stmt::CXXOperatorCallExprClass
: {
391 const auto *OpCall
= cast
<CXXOperatorCallExpr
>(Init
);
392 if (OpCall
->getOperator() == OO_Star
)
393 return isDereferenceOfOpCall(OpCall
, IndexVar
);
394 if (OpCall
->getOperator() == OO_Subscript
) {
395 return OpCall
->getNumArgs() == 2 &&
396 isIndexInSubscriptExpr(OpCall
->getArg(1), IndexVar
);
401 case Stmt::CXXMemberCallExprClass
: {
402 const auto *MemCall
= cast
<CXXMemberCallExpr
>(Init
);
403 // This check is needed because getMethodDecl can return nullptr if the
404 // callee is a member function pointer.
405 const auto *MDecl
= MemCall
->getMethodDecl();
406 if (MDecl
&& !isa
<CXXConversionDecl
>(MDecl
) &&
407 MDecl
->getNameAsString() == "at" && MemCall
->getNumArgs() == 1) {
408 return isIndexInSubscriptExpr(MemCall
->getArg(0), IndexVar
);
419 /// Determines whether the bound of a for loop condition expression is
420 /// the same as the statically computable size of ArrayType.
427 /// This is intended to permit
429 /// for (int i = 0; i < N; ++i) { /* use arr[i] */ }
430 /// for (int i = 0; i < arraysize(arr); ++i) { /* use arr[i] */ }
432 static bool arrayMatchesBoundExpr(ASTContext
*Context
,
433 const QualType
&ArrayType
,
434 const Expr
*ConditionExpr
) {
435 if (!ConditionExpr
|| ConditionExpr
->isValueDependent())
437 const ConstantArrayType
*ConstType
=
438 Context
->getAsConstantArrayType(ArrayType
);
441 std::optional
<llvm::APSInt
> ConditionSize
=
442 ConditionExpr
->getIntegerConstantExpr(*Context
);
445 llvm::APSInt
ArraySize(ConstType
->getSize());
446 return llvm::APSInt::isSameValue(*ConditionSize
, ArraySize
);
449 ForLoopIndexUseVisitor::ForLoopIndexUseVisitor(ASTContext
*Context
,
450 const VarDecl
*IndexVar
,
451 const VarDecl
*EndVar
,
452 const Expr
*ContainerExpr
,
453 const Expr
*ArrayBoundExpr
,
454 bool ContainerNeedsDereference
)
455 : Context(Context
), IndexVar(IndexVar
), EndVar(EndVar
),
456 ContainerExpr(ContainerExpr
), ArrayBoundExpr(ArrayBoundExpr
),
457 ContainerNeedsDereference(ContainerNeedsDereference
),
459 ConfidenceLevel(Confidence::CL_Safe
) {
461 addComponent(ContainerExpr
);
464 bool ForLoopIndexUseVisitor::findAndVerifyUsages(const Stmt
*Body
) {
465 TraverseStmt(const_cast<Stmt
*>(Body
));
466 return OnlyUsedAsIndex
&& ContainerExpr
;
469 void ForLoopIndexUseVisitor::addComponents(const ComponentVector
&Components
) {
470 // FIXME: add sort(on ID)+unique to avoid extra work.
471 for (const auto &I
: Components
)
475 void ForLoopIndexUseVisitor::addComponent(const Expr
*E
) {
476 llvm::FoldingSetNodeID ID
;
477 const Expr
*Node
= E
->IgnoreParenImpCasts();
478 Node
->Profile(ID
, *Context
, true);
479 DependentExprs
.push_back(std::make_pair(Node
, ID
));
482 void ForLoopIndexUseVisitor::addUsage(const Usage
&U
) {
483 SourceLocation Begin
= U
.Range
.getBegin();
484 if (Begin
.isMacroID())
485 Begin
= Context
->getSourceManager().getSpellingLoc(Begin
);
487 if (UsageLocations
.insert(Begin
).second
)
491 /// If the unary operator is a dereference of IndexVar, include it
492 /// as a valid usage and prune the traversal.
494 /// For example, if container.begin() and container.end() both return pointers
495 /// to int, this makes sure that the initialization for `k` is not counted as an
496 /// unconvertible use of the iterator `i`.
498 /// for (int *i = container.begin(), *e = container.end(); i != e; ++i) {
502 bool ForLoopIndexUseVisitor::TraverseUnaryOperator(UnaryOperator
*Uop
) {
503 // If we dereference an iterator that's actually a pointer, count the
505 if (isDereferenceOfUop(Uop
, IndexVar
)) {
506 addUsage(Usage(Uop
));
510 return VisitorBase::TraverseUnaryOperator(Uop
);
513 /// If the member expression is operator-> (overloaded or not) on
514 /// IndexVar, include it as a valid usage and prune the traversal.
516 /// For example, given
518 /// struct Foo { int bar(); int x; };
521 /// the following uses will be considered convertible:
523 /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
524 /// int b = i->bar();
525 /// int k = i->x + 1;
530 /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
531 /// int k = i.insert(1);
533 /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
534 /// int b = e->bar();
538 bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr
*Member
) {
539 const Expr
*Base
= Member
->getBase();
540 const DeclRefExpr
*Obj
= getDeclRef(Base
);
541 const Expr
*ResultExpr
= Member
;
543 if (const auto *Call
=
544 dyn_cast
<CXXOperatorCallExpr
>(Base
->IgnoreParenImpCasts())) {
545 // If operator->() is a MemberExpr containing a CXXOperatorCallExpr, then
546 // the MemberExpr does not have the expression we want. We therefore catch
547 // that instance here.
548 // For example, if vector<Foo>::iterator defines operator->(), then the
549 // example `i->bar()` at the top of this function is a CXXMemberCallExpr
550 // referring to `i->` as the member function called. We want just `i`, so
551 // we take the argument to operator->() as the base object.
552 if (Call
->getOperator() == OO_Arrow
) {
553 assert(Call
->getNumArgs() == 1 &&
554 "Operator-> takes more than one argument");
555 Obj
= getDeclRef(Call
->getArg(0));
557 ExprType
= Call
->getCallReturnType(*Context
);
561 if (Obj
&& exprReferencesVariable(IndexVar
, Obj
)) {
562 // Member calls on the iterator with '.' are not allowed.
563 if (!Member
->isArrow()) {
564 OnlyUsedAsIndex
= false;
568 if (ExprType
.isNull())
569 ExprType
= Obj
->getType();
571 if (!ExprType
->isPointerType())
574 // FIXME: This works around not having the location of the arrow operator.
575 // Consider adding OperatorLoc to MemberExpr?
576 SourceLocation ArrowLoc
= Lexer::getLocForEndOfToken(
577 Base
->getExprLoc(), 0, Context
->getSourceManager(),
578 Context
->getLangOpts());
579 // If something complicated is happening (i.e. the next token isn't an
580 // arrow), give up on making this work.
581 if (ArrowLoc
.isValid()) {
582 addUsage(Usage(ResultExpr
, Usage::UK_MemberThroughArrow
,
583 SourceRange(Base
->getExprLoc(), ArrowLoc
)));
587 return VisitorBase::TraverseMemberExpr(Member
);
590 /// If a member function call is the at() accessor on the container with
591 /// IndexVar as the single argument, include it as a valid usage and prune
594 /// Member calls on other objects will not be permitted.
595 /// Calls on the iterator object are not permitted, unless done through
596 /// operator->(). The one exception is allowing vector::at() for pseudoarrays.
597 bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
598 CXXMemberCallExpr
*MemberCall
) {
600 dyn_cast
<MemberExpr
>(MemberCall
->getCallee()->IgnoreParenImpCasts());
602 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall
);
604 // We specifically allow an accessor named "at" to let STL in, though
605 // this is restricted to pseudo-arrays by requiring a single, integer
607 const IdentifierInfo
*Ident
= Member
->getMemberDecl()->getIdentifier();
608 if (Ident
&& Ident
->isStr("at") && MemberCall
->getNumArgs() == 1) {
609 if (isIndexInSubscriptExpr(Context
, MemberCall
->getArg(0), IndexVar
,
610 Member
->getBase(), ContainerExpr
,
611 ContainerNeedsDereference
)) {
612 addUsage(Usage(MemberCall
));
617 if (containsExpr(Context
, &DependentExprs
, Member
->getBase()))
618 ConfidenceLevel
.lowerTo(Confidence::CL_Risky
);
620 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall
);
623 /// If an overloaded operator call is a dereference of IndexVar or
624 /// a subscript of the container with IndexVar as the single argument,
625 /// include it as a valid usage and prune the traversal.
627 /// For example, given
629 /// struct Foo { int bar(); int x; };
633 /// the following uses will be considered convertible:
635 /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
638 /// for (int i = 0; i < v.size(); ++i) {
639 /// int i = v[i] + 1;
642 bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
643 CXXOperatorCallExpr
*OpCall
) {
644 switch (OpCall
->getOperator()) {
646 if (isDereferenceOfOpCall(OpCall
, IndexVar
)) {
647 addUsage(Usage(OpCall
));
653 if (OpCall
->getNumArgs() != 2)
655 if (isIndexInSubscriptExpr(Context
, OpCall
->getArg(1), IndexVar
,
656 OpCall
->getArg(0), ContainerExpr
,
657 ContainerNeedsDereference
)) {
658 addUsage(Usage(OpCall
));
666 return VisitorBase::TraverseCXXOperatorCallExpr(OpCall
);
669 /// If we encounter an array with IndexVar as the index of an
670 /// ArraySubscriptExpression, note it as a consistent usage and prune the
673 /// For example, given
678 /// This is intended to permit
680 /// for (int i = 0; i < N; ++i) { /* use arr[i] */ }
684 /// for (int i = 0; i < N; ++i) { /* use notArr[i] */ }
686 /// and further checking needs to be done later to ensure that exactly one array
688 bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr
*E
) {
689 Expr
*Arr
= E
->getBase();
690 if (!isIndexInSubscriptExpr(E
->getIdx(), IndexVar
))
691 return VisitorBase::TraverseArraySubscriptExpr(E
);
693 if ((ContainerExpr
&&
694 !areSameExpr(Context
, Arr
->IgnoreParenImpCasts(),
695 ContainerExpr
->IgnoreParenImpCasts())) ||
696 !arrayMatchesBoundExpr(Context
, Arr
->IgnoreImpCasts()->getType(),
698 // If we have already discovered the array being indexed and this isn't it
699 // or this array doesn't match, mark this loop as unconvertible.
700 OnlyUsedAsIndex
= false;
701 return VisitorBase::TraverseArraySubscriptExpr(E
);
711 /// If we encounter a reference to IndexVar in an unpruned branch of the
712 /// traversal, mark this loop as unconvertible.
714 /// This determines the set of convertible loops: any usages of IndexVar
715 /// not explicitly considered convertible by this traversal will be caught by
718 /// Additionally, if the container expression is more complex than just a
719 /// DeclRefExpr, and some part of it is appears elsewhere in the loop, lower
720 /// our confidence in the transformation.
722 /// For example, these are not permitted:
724 /// for (int i = 0; i < N; ++i) { printf("arr[%d] = %d", i, arr[i]); }
725 /// for (vector<int>::iterator i = container.begin(), e = container.end();
728 /// for (vector<int>::iterator i = container.begin(), e = container.end();
731 /// printf("%d", *i);
734 /// And these will raise the risk level:
738 /// for (int j = 0; j < 20; ++j)
739 /// int k = arr[l][j] + l; // using l outside arr[l] is considered risky
740 /// for (int i = 0; i < obj.getVector().size(); ++i)
741 /// obj.foo(10); // using `obj` is considered risky
743 bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr
*E
) {
744 const ValueDecl
*TheDecl
= E
->getDecl();
745 if (areSameVariable(IndexVar
, TheDecl
) ||
746 exprReferencesVariable(IndexVar
, E
) || areSameVariable(EndVar
, TheDecl
) ||
747 exprReferencesVariable(EndVar
, E
))
748 OnlyUsedAsIndex
= false;
749 if (containsExpr(Context
, &DependentExprs
, E
))
750 ConfidenceLevel
.lowerTo(Confidence::CL_Risky
);
754 /// If the loop index is captured by a lambda, replace this capture
755 /// by the range-for loop variable.
759 /// for (int i = 0; i < N; ++i) {
760 /// auto f = [v, i](int k) {
761 /// printf("%d\n", v[i] + k);
767 /// Will be replaced by:
769 /// for (auto & elem : v) {
770 /// auto f = [v, elem](int k) {
771 /// printf("%d\n", elem + k);
776 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr
*LE
,
777 const LambdaCapture
*C
,
779 if (C
->capturesVariable()) {
780 const ValueDecl
*VDecl
= C
->getCapturedVar();
781 if (areSameVariable(IndexVar
, VDecl
)) {
782 // FIXME: if the index is captured, it will count as an usage and the
783 // alias (if any) won't work, because it is only used in case of having
784 // exactly one usage.
785 addUsage(Usage(nullptr,
786 C
->getCaptureKind() == LCK_ByCopy
? Usage::UK_CaptureByCopy
787 : Usage::UK_CaptureByRef
,
791 return VisitorBase::TraverseLambdaCapture(LE
, C
, Init
);
794 /// If we find that another variable is created just to refer to the loop
795 /// element, note it for reuse as the loop variable.
797 /// See the comments for isAliasDecl.
798 bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt
*S
) {
799 if (!AliasDecl
&& S
->isSingleDecl() &&
800 isAliasDecl(Context
, S
->getSingleDecl(), IndexVar
)) {
802 if (CurrStmtParent
) {
803 if (isa
<IfStmt
>(CurrStmtParent
) || isa
<WhileStmt
>(CurrStmtParent
) ||
804 isa
<SwitchStmt
>(CurrStmtParent
))
805 ReplaceWithAliasUse
= true;
806 else if (isa
<ForStmt
>(CurrStmtParent
)) {
807 if (cast
<ForStmt
>(CurrStmtParent
)->getConditionVariableDeclStmt() == S
)
808 ReplaceWithAliasUse
= true;
810 // It's assumed S came the for loop's init clause.
811 AliasFromForInit
= true;
819 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt
*S
) {
820 // If this is an initialization expression for a lambda capture, prune the
821 // traversal so that we don't end up diagnosing the contained DeclRefExpr as
822 // inconsistent usage. No need to record the usage here -- this is done in
823 // TraverseLambdaCapture().
824 if (const auto *LE
= dyn_cast_or_null
<LambdaExpr
>(NextStmtParent
)) {
825 // Any child of a LambdaExpr that isn't the body is an initialization
827 if (S
!= LE
->getBody()) {
832 // All this pointer swapping is a mechanism for tracking immediate parentage
834 const Stmt
*OldNextParent
= NextStmtParent
;
835 CurrStmtParent
= NextStmtParent
;
837 bool Result
= VisitorBase::TraverseStmt(S
);
838 NextStmtParent
= OldNextParent
;
842 std::string
VariableNamer::createIndexName() {
843 // FIXME: Add in naming conventions to handle:
844 // - How to handle conflicts.
845 // - An interactive process for naming.
846 std::string IteratorName
;
847 StringRef ContainerName
;
849 ContainerName
= TheContainer
->getName();
851 size_t Len
= ContainerName
.size();
852 if (Len
> 1 && ContainerName
.endswith(Style
== NS_UpperCase
? "S" : "s")) {
853 IteratorName
= std::string(ContainerName
.substr(0, Len
- 1));
854 // E.g.: (auto thing : things)
855 if (!declarationExists(IteratorName
) || IteratorName
== OldIndex
->getName())
859 if (Len
> 2 && ContainerName
.endswith(Style
== NS_UpperCase
? "S_" : "s_")) {
860 IteratorName
= std::string(ContainerName
.substr(0, Len
- 2));
861 // E.g.: (auto thing : things_)
862 if (!declarationExists(IteratorName
) || IteratorName
== OldIndex
->getName())
866 return std::string(OldIndex
->getName());
869 /// Determines whether or not the name \a Symbol conflicts with
870 /// language keywords or defined macros. Also checks if the name exists in
871 /// LoopContext, any of its parent contexts, or any of its child statements.
873 /// We also check to see if the same identifier was generated by this loop
874 /// converter in a loop nested within SourceStmt.
875 bool VariableNamer::declarationExists(StringRef Symbol
) {
876 assert(Context
!= nullptr && "Expected an ASTContext");
877 IdentifierInfo
&Ident
= Context
->Idents
.get(Symbol
);
879 // Check if the symbol is not an identifier (ie. is a keyword or alias).
880 if (!isAnyIdentifier(Ident
.getTokenID()))
883 // Check for conflicting macro definitions.
884 if (Ident
.hasMacroDefinition())
887 // Determine if the symbol was generated in a parent context.
888 for (const Stmt
*S
= SourceStmt
; S
!= nullptr; S
= ReverseAST
->lookup(S
)) {
889 StmtGeneratedVarNameMap::const_iterator I
= GeneratedDecls
->find(S
);
890 if (I
!= GeneratedDecls
->end() && I
->second
== Symbol
)
894 // FIXME: Rather than detecting conflicts at their usages, we should check the
896 // For some reason, lookup() always returns the pair (NULL, NULL) because its
897 // StoredDeclsMap is not initialized (i.e. LookupPtr.getInt() is false inside
898 // of DeclContext::lookup()). Why is this?
900 // Finally, determine if the symbol was used in the loop or a child context.
901 DeclFinderASTVisitor
DeclFinder(std::string(Symbol
), GeneratedDecls
);
902 return DeclFinder
.findUsages(SourceStmt
);
905 } // namespace clang::tidy::modernize