1 //===--- LoopConvertUtils.h - clang-tidy ------------------------*- C++ -*-===//
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 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/SmallSet.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringRef.h"
25 namespace clang::tidy::modernize
{
34 /// A map used to walk the AST in reverse: maps child Stmt to parent Stmt.
35 using StmtParentMap
= llvm::DenseMap
<const clang::Stmt
*, const clang::Stmt
*>;
37 /// A map used to walk the AST in reverse:
38 /// maps VarDecl to the to parent DeclStmt.
40 llvm::DenseMap
<const clang::VarDecl
*, const clang::DeclStmt
*>;
42 /// A map used to track which variables have been removed by a refactoring pass.
43 /// It maps the parent ForStmt to the removed index variable's VarDecl.
44 using ReplacedVarsMap
=
45 llvm::DenseMap
<const clang::ForStmt
*, const clang::VarDecl
*>;
47 /// A map used to remember the variable names generated in a Stmt
48 using StmtGeneratedVarNameMap
=
49 llvm::DenseMap
<const clang::Stmt
*, std::string
>;
51 /// A vector used to store the AST subtrees of an Expr.
52 using ComponentVector
= llvm::SmallVector
<const clang::Expr
*, 16>;
54 /// Class used build the reverse AST properties needed to detect
55 /// name conflicts and free variables.
56 class StmtAncestorASTVisitor
57 : public clang::RecursiveASTVisitor
<StmtAncestorASTVisitor
> {
59 StmtAncestorASTVisitor() { StmtStack
.push_back(nullptr); }
61 /// Run the analysis on the AST.
63 /// In case we're running this analysis multiple times, don't repeat the work.
64 void gatherAncestors(ASTContext
&Ctx
) {
65 if (StmtAncestors
.empty())
69 /// Accessor for StmtAncestors.
70 const StmtParentMap
&getStmtToParentStmtMap() { return StmtAncestors
; }
72 /// Accessor for DeclParents.
73 const DeclParentMap
&getDeclToParentStmtMap() { return DeclParents
; }
75 friend class clang::RecursiveASTVisitor
<StmtAncestorASTVisitor
>;
78 StmtParentMap StmtAncestors
;
79 DeclParentMap DeclParents
;
80 llvm::SmallVector
<const clang::Stmt
*, 16> StmtStack
;
82 bool TraverseStmt(clang::Stmt
*Statement
);
83 bool VisitDeclStmt(clang::DeclStmt
*Statement
);
86 /// Class used to find the variables and member expressions on which an
87 /// arbitrary expression depends.
88 class ComponentFinderASTVisitor
89 : public clang::RecursiveASTVisitor
<ComponentFinderASTVisitor
> {
91 ComponentFinderASTVisitor() = default;
93 /// Find the components of an expression and place them in a ComponentVector.
94 void findExprComponents(const clang::Expr
*SourceExpr
) {
95 TraverseStmt(const_cast<clang::Expr
*>(SourceExpr
));
98 /// Accessor for Components.
99 const ComponentVector
&getComponents() { return Components
; }
101 friend class clang::RecursiveASTVisitor
<ComponentFinderASTVisitor
>;
104 ComponentVector Components
;
106 bool VisitDeclRefExpr(clang::DeclRefExpr
*E
);
107 bool VisitMemberExpr(clang::MemberExpr
*Member
);
110 /// Class used to determine if an expression is dependent on a variable declared
111 /// inside of the loop where it would be used.
112 class DependencyFinderASTVisitor
113 : public clang::RecursiveASTVisitor
<DependencyFinderASTVisitor
> {
115 DependencyFinderASTVisitor(const StmtParentMap
*StmtParents
,
116 const DeclParentMap
*DeclParents
,
117 const ReplacedVarsMap
*ReplacedVars
,
118 const clang::Stmt
*ContainingStmt
)
119 : StmtParents(StmtParents
), DeclParents(DeclParents
),
120 ContainingStmt(ContainingStmt
), ReplacedVars(ReplacedVars
) {}
122 /// Run the analysis on Body, and return true iff the expression
123 /// depends on some variable declared within ContainingStmt.
125 /// This is intended to protect against hoisting the container expression
126 /// outside of an inner context if part of that expression is declared in that
131 /// const int N = 10, M = 20;
135 /// for (int i = 0; i < M; ++i) {
136 /// int k = getRow();
137 /// printf("%d:", arr[k][i]);
140 /// At first glance, this loop looks like it could be changed to
142 /// for (int elem : arr[k]) {
143 /// int k = getIndex();
144 /// printf("%d:", elem);
147 /// But this is malformed, since `k` is used before it is defined!
149 /// In order to avoid this, this class looks at the container expression
150 /// `arr[k]` and decides whether or not it contains a sub-expression declared
151 /// within the loop body.
152 bool dependsOnInsideVariable(const clang::Stmt
*Body
) {
153 DependsOnInsideVariable
= false;
154 TraverseStmt(const_cast<clang::Stmt
*>(Body
));
155 return DependsOnInsideVariable
;
158 friend class clang::RecursiveASTVisitor
<DependencyFinderASTVisitor
>;
161 const StmtParentMap
*StmtParents
;
162 const DeclParentMap
*DeclParents
;
163 const clang::Stmt
*ContainingStmt
;
164 const ReplacedVarsMap
*ReplacedVars
;
165 bool DependsOnInsideVariable
;
167 bool VisitVarDecl(clang::VarDecl
*V
);
168 bool VisitDeclRefExpr(clang::DeclRefExpr
*D
);
171 /// Class used to determine if any declarations used in a Stmt would conflict
172 /// with a particular identifier. This search includes the names that don't
173 /// actually appear in the AST (i.e. created by a refactoring tool) by including
174 /// a map from Stmts to generated names associated with those stmts.
175 class DeclFinderASTVisitor
176 : public clang::RecursiveASTVisitor
<DeclFinderASTVisitor
> {
178 DeclFinderASTVisitor(const StringRef
&Name
,
179 const StmtGeneratedVarNameMap
*GeneratedDecls
)
180 : Name(Name
), GeneratedDecls(GeneratedDecls
) {}
182 /// Attempts to find any usages of variables name Name in Body, returning
183 /// true when it is used in Body. This includes the generated loop variables
184 /// of ForStmts which have already been transformed.
185 bool findUsages(const clang::Stmt
*Body
) {
187 TraverseStmt(const_cast<clang::Stmt
*>(Body
));
191 friend class clang::RecursiveASTVisitor
<DeclFinderASTVisitor
>;
195 /// GeneratedDecls keeps track of ForStmts which have been transformed,
196 /// mapping each modified ForStmt to the variable generated in the loop.
197 const StmtGeneratedVarNameMap
*GeneratedDecls
;
200 bool VisitForStmt(clang::ForStmt
*);
201 bool VisitNamedDecl(clang::NamedDecl
*);
202 bool VisitDeclRefExpr(clang::DeclRefExpr
*);
203 bool VisitTypeLoc(clang::TypeLoc
);
206 /// The information needed to describe a valid convertible usage
207 /// of an array index or iterator.
210 // Regular usages of the loop index (the ones not specified below). Some
213 // int X = 8 * Arr[i];
215 // f(param1, param2, *It);
217 // if (Vec[i].SomeBool) {}
221 // Indicates whether this is an access to a member through the arrow
222 // operator on pointers or iterators.
223 UK_MemberThroughArrow
,
224 // If the variable is being captured by a lambda, indicates whether the
225 // capture was done by value or by reference.
229 // The expression that is going to be converted. Null in case of lambda
231 const Expr
*Expression
;
235 // Range that covers this usage.
238 explicit Usage(const Expr
*E
)
239 : Expression(E
), Kind(UK_Default
), Range(Expression
->getSourceRange()) {}
240 Usage(const Expr
*E
, UsageKind Kind
, SourceRange Range
)
241 : Expression(E
), Kind(Kind
), Range(std::move(Range
)) {}
244 /// A class to encapsulate lowering of the tool's confidence level.
248 // Transformations that are likely to change semantics.
251 // Transformations that might change semantics.
254 // Transformations that will not change semantics.
257 /// Initialize confidence level.
258 explicit Confidence(Confidence::Level Level
) : CurrentLevel(Level
) {}
260 /// Lower the internal confidence level to Level, but do not raise it.
261 void lowerTo(Confidence::Level Level
) {
262 CurrentLevel
= std::min(Level
, CurrentLevel
);
265 /// Return the internal confidence level.
266 Level
getLevel() const { return CurrentLevel
; }
272 // The main computational result of ForLoopIndexVisitor.
273 using UsageResult
= llvm::SmallVector
<Usage
, 8>;
275 // General functions used by ForLoopIndexUseVisitor and LoopConvertCheck.
276 const Expr
*digThroughConstructorsConversions(const Expr
*E
);
277 bool areSameExpr(ASTContext
*Context
, const Expr
*First
, const Expr
*Second
);
278 const DeclRefExpr
*getDeclRef(const Expr
*E
);
279 bool areSameVariable(const ValueDecl
*First
, const ValueDecl
*Second
);
281 /// Discover usages of expressions consisting of index or iterator
284 /// Given an index variable, recursively crawls a for loop to discover if the
285 /// index variable is used in a way consistent with range-based for loop access.
286 class ForLoopIndexUseVisitor
287 : public RecursiveASTVisitor
<ForLoopIndexUseVisitor
> {
289 ForLoopIndexUseVisitor(ASTContext
*Context
, const VarDecl
*IndexVar
,
290 const VarDecl
*EndVar
, const Expr
*ContainerExpr
,
291 const Expr
*ArrayBoundExpr
,
292 bool ContainerNeedsDereference
);
294 /// Finds all uses of IndexVar in Body, placing all usages in Usages,
295 /// and returns true if IndexVar was only used in a way consistent with a
296 /// range-based for loop.
298 /// The general strategy is to reject any DeclRefExprs referencing IndexVar,
299 /// with the exception of certain acceptable patterns.
300 /// For arrays, the DeclRefExpr for IndexVar must appear as the index of an
301 /// ArraySubscriptExpression. Iterator-based loops may dereference
302 /// IndexVar or call methods through operator-> (builtin or overloaded).
303 /// Array-like containers may use IndexVar as a parameter to the at() member
304 /// function and in overloaded operator[].
305 bool findAndVerifyUsages(const Stmt
*Body
);
307 /// Add a set of components that we should consider relevant to the
309 void addComponents(const ComponentVector
&Components
);
311 /// Accessor for Usages.
312 const UsageResult
&getUsages() const { return Usages
; }
314 /// Adds the Usage if it was not added before.
315 void addUsage(const Usage
&U
);
317 /// Get the container indexed by IndexVar, if any.
318 const Expr
*getContainerIndexed() const { return ContainerExpr
; }
320 /// Returns the statement declaring the variable created as an alias
321 /// for the loop element, if any.
322 const DeclStmt
*getAliasDecl() const { return AliasDecl
; }
324 /// Accessor for ConfidenceLevel.
325 Confidence::Level
getConfidenceLevel() const {
326 return ConfidenceLevel
.getLevel();
329 /// Indicates if the alias declaration was in a place where it cannot
330 /// simply be removed but rather replaced with a use of the alias variable.
331 /// For example, variables declared in the condition of an if, switch, or for
333 bool aliasUseRequired() const { return ReplaceWithAliasUse
; }
335 /// Indicates if the alias declaration came from the init clause of a
336 /// nested for loop. SourceRanges provided by Clang for DeclStmts in this
337 /// case need to be adjusted.
338 bool aliasFromForInit() const { return AliasFromForInit
; }
341 /// Typedef used in CRTP functions.
342 using VisitorBase
= RecursiveASTVisitor
<ForLoopIndexUseVisitor
>;
343 friend class RecursiveASTVisitor
<ForLoopIndexUseVisitor
>;
345 /// Overriden methods for RecursiveASTVisitor's traversal.
346 bool TraverseArraySubscriptExpr(ArraySubscriptExpr
*E
);
347 bool TraverseCXXMemberCallExpr(CXXMemberCallExpr
*MemberCall
);
348 bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr
*OpCall
);
349 bool TraverseLambdaCapture(LambdaExpr
*LE
, const LambdaCapture
*C
,
351 bool TraverseMemberExpr(MemberExpr
*Member
);
352 bool TraverseUnaryOperator(UnaryOperator
*Uop
);
353 bool VisitDeclRefExpr(DeclRefExpr
*E
);
354 bool VisitDeclStmt(DeclStmt
*S
);
355 bool TraverseStmt(Stmt
*S
);
357 /// Add an expression to the list of expressions on which the container
358 /// expression depends.
359 void addComponent(const Expr
*E
);
361 // Input member variables:
363 /// The index variable's VarDecl.
364 const VarDecl
*IndexVar
;
365 /// The loop's 'end' variable, which cannot be mentioned at all.
366 const VarDecl
*EndVar
;
367 /// The Expr which refers to the container.
368 const Expr
*ContainerExpr
;
369 /// The Expr which refers to the terminating condition for array-based loops.
370 const Expr
*ArrayBoundExpr
;
371 bool ContainerNeedsDereference
;
373 // Output member variables:
374 /// A container which holds all usages of IndexVar as the index of
375 /// ArraySubscriptExpressions.
377 llvm::SmallSet
<SourceLocation
, 8> UsageLocations
;
378 bool OnlyUsedAsIndex
= true;
379 /// The DeclStmt for an alias to the container element.
380 const DeclStmt
*AliasDecl
= nullptr;
381 Confidence ConfidenceLevel
;
382 /// A list of expressions on which ContainerExpr depends.
384 /// If any of these expressions are encountered outside of an acceptable usage
385 /// of the loop element, lower our confidence level.
386 llvm::SmallVector
<std::pair
<const Expr
*, llvm::FoldingSetNodeID
>, 16>
389 /// The parent-in-waiting. Will become the real parent once we traverse down
390 /// one level in the AST.
391 const Stmt
*NextStmtParent
= nullptr;
392 /// The actual parent of a node when Visit*() calls are made. Only the
393 /// parentage of DeclStmt's to possible iteration/selection statements is of
395 const Stmt
*CurrStmtParent
= nullptr;
397 /// \see aliasUseRequired().
398 bool ReplaceWithAliasUse
= false;
399 /// \see aliasFromForInit().
400 bool AliasFromForInit
= false;
403 struct TUTrackingInfo
{
404 /// Reset and initialize per-TU tracking information.
406 /// Must be called before using container accessors.
407 TUTrackingInfo() : ParentFinder(new StmtAncestorASTVisitor
) {}
409 StmtAncestorASTVisitor
&getParentFinder() { return *ParentFinder
; }
410 StmtGeneratedVarNameMap
&getGeneratedDecls() { return GeneratedDecls
; }
411 ReplacedVarsMap
&getReplacedVars() { return ReplacedVars
; }
414 std::unique_ptr
<StmtAncestorASTVisitor
> ParentFinder
;
415 StmtGeneratedVarNameMap GeneratedDecls
;
416 ReplacedVarsMap ReplacedVars
;
419 /// Create names for generated variables within a particular statement.
421 /// VariableNamer uses a DeclContext as a reference point, checking for any
422 /// conflicting declarations higher up in the context or within SourceStmt.
423 /// It creates a variable name using hints from a source container and the old
424 /// index, if they exist.
425 class VariableNamer
{
427 // Supported naming styles.
435 VariableNamer(StmtGeneratedVarNameMap
*GeneratedDecls
,
436 const StmtParentMap
*ReverseAST
, const clang::Stmt
*SourceStmt
,
437 const clang::VarDecl
*OldIndex
,
438 const clang::ValueDecl
*TheContainer
,
439 const clang::ASTContext
*Context
, NamingStyle Style
)
440 : GeneratedDecls(GeneratedDecls
), ReverseAST(ReverseAST
),
441 SourceStmt(SourceStmt
), OldIndex(OldIndex
), TheContainer(TheContainer
),
442 Context(Context
), Style(Style
) {}
444 /// Generate a new index name.
446 /// Generates the name to be used for an inserted iterator. It relies on
447 /// declarationExists() to determine that there are no naming conflicts, and
448 /// tries to use some hints from the container name and the old index name.
449 std::string
createIndexName();
452 StmtGeneratedVarNameMap
*GeneratedDecls
;
453 const StmtParentMap
*ReverseAST
;
454 const clang::Stmt
*SourceStmt
;
455 const clang::VarDecl
*OldIndex
;
456 const clang::ValueDecl
*TheContainer
;
457 const clang::ASTContext
*Context
;
458 const NamingStyle Style
;
460 // Determine whether or not a declaration that would conflict with Symbol
461 // exists in an outer context or in any statement contained in SourceStmt.
462 bool declarationExists(llvm::StringRef Symbol
);
465 } // namespace clang::tidy::modernize
467 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H