clang-tools 23.0.0git
LoopConvertUtils.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOPCONVERTUTILS_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOPCONVERTUTILS_H
11
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 <algorithm>
19#include <memory>
20#include <string>
21#include <utility>
22
23namespace clang::tidy::modernize {
24
31
32/// A map used to walk the AST in reverse: maps child Stmt to parent Stmt.
33using StmtParentMap = llvm::DenseMap<const Stmt *, const Stmt *>;
34
35/// A map used to walk the AST in reverse:
36/// maps VarDecl to the to parent DeclStmt.
37using DeclParentMap = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
38
39/// A map used to track which variables have been removed by a refactoring pass.
40/// It maps the parent ForStmt to the removed index variable's VarDecl.
41using ReplacedVarsMap = llvm::DenseMap<const ForStmt *, const VarDecl *>;
42
43/// A map used to remember the variable names generated in a Stmt
44using StmtGeneratedVarNameMap = llvm::DenseMap<const Stmt *, std::string>;
45
46/// A vector used to store the AST subtrees of an Expr.
48
49/// Class used build the reverse AST properties needed to detect
50/// name conflicts and free variables.
52 : public RecursiveASTVisitor<StmtAncestorASTVisitor> {
53public:
54 StmtAncestorASTVisitor() { StmtStack.push_back(nullptr); }
55
56 /// Run the analysis on the AST.
57 ///
58 /// In case we're running this analysis multiple times, don't repeat the work.
59 void gatherAncestors(ASTContext &Ctx) {
60 if (StmtAncestors.empty())
61 TraverseAST(Ctx);
62 }
63
64 /// Accessor for StmtAncestors.
65 const StmtParentMap &getStmtToParentStmtMap() { return StmtAncestors; }
66
67 /// Accessor for DeclParents.
68 const DeclParentMap &getDeclToParentStmtMap() { return DeclParents; }
69
70 friend class RecursiveASTVisitor<StmtAncestorASTVisitor>;
71
72private:
73 StmtParentMap StmtAncestors;
74 DeclParentMap DeclParents;
76
77 bool TraverseStmt(Stmt *Statement);
78 bool VisitDeclStmt(DeclStmt *Statement);
79};
80
81/// Class used to find the variables and member expressions on which an
82/// arbitrary expression depends.
84 : public RecursiveASTVisitor<ComponentFinderASTVisitor> {
85public:
87
88 /// Find the components of an expression and place them in a ComponentVector.
89 void findExprComponents(const Expr *SourceExpr) {
90 TraverseStmt(const_cast<Expr *>(SourceExpr));
91 }
92
93 /// Accessor for Components.
94 const ComponentVector &getComponents() { return Components; }
95
96 friend class RecursiveASTVisitor<ComponentFinderASTVisitor>;
97
98private:
99 ComponentVector Components;
100
101 bool VisitDeclRefExpr(DeclRefExpr *E);
102 bool VisitMemberExpr(MemberExpr *Member);
103};
104
105/// Class used to determine if an expression is dependent on a variable declared
106/// inside of the loop where it would be used.
108 : public RecursiveASTVisitor<DependencyFinderASTVisitor> {
109public:
111 const DeclParentMap *DeclParents,
112 const ReplacedVarsMap *ReplacedVars,
113 const Stmt *ContainingStmt)
114 : StmtParents(StmtParents), DeclParents(DeclParents),
115 ContainingStmt(ContainingStmt), ReplacedVars(ReplacedVars) {}
116
117 /// Run the analysis on Body, and return true iff the expression
118 /// depends on some variable declared within ContainingStmt.
119 ///
120 /// This is intended to protect against hoisting the container expression
121 /// outside of an inner context if part of that expression is declared in that
122 /// inner context.
123 ///
124 /// For example,
125 /// \code
126 /// const int N = 10, M = 20;
127 /// int arr[N][M];
128 /// int getRow();
129 ///
130 /// for (int i = 0; i < M; ++i) {
131 /// int k = getRow();
132 /// printf("%d:", arr[k][i]);
133 /// }
134 /// \endcode
135 /// At first glance, this loop looks like it could be changed to
136 /// \code
137 /// for (int elem : arr[k]) {
138 /// int k = getIndex();
139 /// printf("%d:", elem);
140 /// }
141 /// \endcode
142 /// But this is malformed, since `k` is used before it is defined!
143 ///
144 /// In order to avoid this, this class looks at the container expression
145 /// `arr[k]` and decides whether or not it contains a sub-expression declared
146 /// within the loop body.
147 bool dependsOnInsideVariable(const Stmt *Body) {
148 DependsOnInsideVariable = false;
149 TraverseStmt(const_cast<Stmt *>(Body));
150 return DependsOnInsideVariable;
151 }
152
153 friend class RecursiveASTVisitor<DependencyFinderASTVisitor>;
154
155private:
156 const StmtParentMap *StmtParents;
157 const DeclParentMap *DeclParents;
158 const Stmt *ContainingStmt;
159 const ReplacedVarsMap *ReplacedVars;
160 bool DependsOnInsideVariable;
161
162 bool VisitVarDecl(VarDecl *V);
163 bool VisitDeclRefExpr(DeclRefExpr *D);
164};
165
166/// Class used to determine if any declarations used in a Stmt would conflict
167/// with a particular identifier. This search includes the names that don't
168/// actually appear in the AST (i.e. created by a refactoring tool) by including
169/// a map from Stmts to generated names associated with those stmts.
170class DeclFinderASTVisitor : public RecursiveASTVisitor<DeclFinderASTVisitor> {
171public:
172 DeclFinderASTVisitor(const StringRef &Name,
173 const StmtGeneratedVarNameMap *GeneratedDecls)
174 : Name(Name), GeneratedDecls(GeneratedDecls) {}
175
176 /// Attempts to find any usages of variables name Name in Body, returning
177 /// true when it is used in Body. This includes the generated loop variables
178 /// of ForStmts which have already been transformed.
179 bool findUsages(const Stmt *Body) {
180 Found = false;
181 TraverseStmt(const_cast<Stmt *>(Body));
182 return Found;
183 }
184
185 friend class RecursiveASTVisitor<DeclFinderASTVisitor>;
186
187private:
188 std::string Name;
189 /// GeneratedDecls keeps track of ForStmts which have been transformed,
190 /// mapping each modified ForStmt to the variable generated in the loop.
191 const StmtGeneratedVarNameMap *GeneratedDecls;
192 bool Found = false;
193
194 bool VisitForStmt(ForStmt *);
195 bool VisitNamedDecl(NamedDecl *);
196 bool VisitDeclRefExpr(DeclRefExpr *);
197 bool VisitTypeLoc(TypeLoc);
198};
199
200/// The information needed to describe a valid convertible usage
201/// of an array index or iterator.
202struct Usage {
204 // Regular usages of the loop index (the ones not specified below). Some
205 // examples:
206 // \code
207 // int X = 8 * Arr[i];
208 // ^~~~~~
209 // f(param1, param2, *It);
210 // ^~~
211 // if (Vec[i].SomeBool) {}
212 // ^~~~~~
213 // \endcode
215 // Indicates whether this is an access to a member through the arrow
216 // operator on pointers or iterators.
218 // If the variable is being captured by a lambda, indicates whether the
219 // capture was done by value or by reference.
222 };
223 // The expression that is going to be converted. Null in case of lambda
224 // captures.
225 const Expr *Expression;
226
228
229 // Range that covers this usage.
230 SourceRange Range;
231
232 explicit Usage(const Expr *E)
233 : Expression(E), Kind(UK_Default), Range(Expression->getSourceRange()) {}
234 Usage(const Expr *E, UsageKind Kind, SourceRange Range)
235 : Expression(E), Kind(Kind), Range(std::move(Range)) {}
236};
237
238/// A class to encapsulate lowering of the tool's confidence level.
240public:
241 enum Level {
242 // Transformations that are likely to change semantics.
244
245 // Transformations that might change semantics.
247
248 // Transformations that will not change semantics.
250 };
251 /// Initialize confidence level.
252 explicit Confidence(Confidence::Level Level) : CurrentLevel(Level) {}
253
254 /// Lower the internal confidence level to Level, but do not raise it.
256 CurrentLevel = std::min(Level, CurrentLevel);
257 }
258
259 /// Return the internal confidence level.
260 Level getLevel() const { return CurrentLevel; }
261
262private:
263 Level CurrentLevel;
264};
265
266// The main computational result of ForLoopIndexVisitor.
268
269// General functions used by ForLoopIndexUseVisitor and LoopConvertCheck.
270const Expr *digThroughConstructorsConversions(const Expr *E);
271bool areSameExpr(const ASTContext *Context, const Expr *First,
272 const Expr *Second);
273const DeclRefExpr *getDeclRef(const Expr *E);
274bool areSameVariable(const ValueDecl *First, const ValueDecl *Second);
275
276/// Discover usages of expressions consisting of index or iterator
277/// access.
278///
279/// Given an index variable, recursively crawls a for loop to discover if the
280/// index variable is used in a way consistent with range-based for loop access.
282 : public RecursiveASTVisitor<ForLoopIndexUseVisitor> {
283public:
284 ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar,
285 const VarDecl *EndVar, const Expr *ContainerExpr,
286 const Expr *ArrayBoundExpr,
287 bool ContainerNeedsDereference);
288
289 /// Finds all uses of IndexVar in Body, placing all usages in Usages,
290 /// and returns true if IndexVar was only used in a way consistent with a
291 /// range-based for loop.
292 ///
293 /// The general strategy is to reject any DeclRefExprs referencing IndexVar,
294 /// with the exception of certain acceptable patterns.
295 /// For arrays, the DeclRefExpr for IndexVar must appear as the index of an
296 /// ArraySubscriptExpression. Iterator-based loops may dereference
297 /// IndexVar or call methods through operator-> (builtin or overloaded).
298 /// Array-like containers may use IndexVar as a parameter to the at() member
299 /// function and in overloaded operator[].
300 bool findAndVerifyUsages(const Stmt *Body);
301
302 /// Add a set of components that we should consider relevant to the
303 /// container.
304 void addComponents(const ComponentVector &Components);
305
306 /// Accessor for Usages.
307 const UsageResult &getUsages() const { return Usages; }
308
309 /// Adds the Usage if it was not added before.
310 void addUsage(const Usage &U);
311
312 /// Get the container indexed by IndexVar, if any.
313 const Expr *getContainerIndexed() const { return ContainerExpr; }
314
315 /// Returns the statement declaring the variable created as an alias
316 /// for the loop element, if any.
317 const DeclStmt *getAliasDecl() const { return AliasDecl; }
318
319 /// Accessor for ConfidenceLevel.
321 return ConfidenceLevel.getLevel();
322 }
323
324 /// Indicates if the alias declaration was in a place where it cannot
325 /// simply be removed but rather replaced with a use of the alias variable.
326 /// For example, variables declared in the condition of an if, switch, or for
327 /// stmt.
328 bool aliasUseRequired() const { return ReplaceWithAliasUse; }
329
330 /// Indicates if the alias declaration came from the init clause of a
331 /// nested for loop. SourceRanges provided by Clang for DeclStmts in this
332 /// case need to be adjusted.
333 bool aliasFromForInit() const { return AliasFromForInit; }
334
335private:
336 /// Typedef used in CRTP functions.
337 using VisitorBase = RecursiveASTVisitor<ForLoopIndexUseVisitor>;
338 friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>;
339
340 /// Overriden methods for RecursiveASTVisitor's traversal.
341 bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
342 bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
343 bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
344 bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
345 Expr *Init);
346 bool TraverseMemberExpr(MemberExpr *Member);
347 bool TraverseUnaryOperator(UnaryOperator *Uop);
348 bool VisitDeclRefExpr(DeclRefExpr *E);
349 bool VisitDeclStmt(DeclStmt *S);
350 bool TraverseStmt(Stmt *S);
351
352 bool traverseStmtImpl(Stmt *S);
353
354 /// Add an expression to the list of expressions on which the container
355 /// expression depends.
356 void addComponent(const Expr *E);
357
358 // Input member variables:
359 ASTContext *Context;
360 /// The index variable's VarDecl.
361 const VarDecl *IndexVar;
362 /// The loop's 'end' variable, which cannot be mentioned at all.
363 const VarDecl *EndVar;
364 /// The Expr which refers to the container.
365 const Expr *ContainerExpr;
366 /// The Expr which refers to the terminating condition for array-based loops.
367 const Expr *ArrayBoundExpr;
368 bool ContainerNeedsDereference;
369
370 // Output member variables:
371 /// A container which holds all usages of IndexVar as the index of
372 /// ArraySubscriptExpressions.
373 UsageResult Usages;
374 llvm::SmallSet<SourceLocation, 8> UsageLocations;
375 bool OnlyUsedAsIndex = true;
376 /// The DeclStmt for an alias to the container element.
377 const DeclStmt *AliasDecl = nullptr;
378 Confidence ConfidenceLevel;
379 /// A list of expressions on which ContainerExpr depends.
380 ///
381 /// If any of these expressions are encountered outside of an acceptable usage
382 /// of the loop element, lower our confidence level.
384 DependentExprs;
385
386 /// The parent-in-waiting. Will become the real parent once we traverse down
387 /// one level in the AST.
388 const Stmt *NextStmtParent = nullptr;
389 /// The actual parent of a node when Visit*() calls are made. Only the
390 /// parentage of DeclStmt's to possible iteration/selection statements is of
391 /// importance.
392 const Stmt *CurrStmtParent = nullptr;
393
394 /// \see aliasUseRequired().
395 bool ReplaceWithAliasUse = false;
396 /// \see aliasFromForInit().
397 bool AliasFromForInit = false;
398};
399
401 /// Reset and initialize per-TU tracking information.
402 ///
403 /// Must be called before using container accessors.
404 TUTrackingInfo() : ParentFinder(new StmtAncestorASTVisitor) {}
405
406 StmtAncestorASTVisitor &getParentFinder() { return *ParentFinder; }
407 StmtGeneratedVarNameMap &getGeneratedDecls() { return GeneratedDecls; }
408 ReplacedVarsMap &getReplacedVars() { return ReplacedVars; }
409
410private:
411 std::unique_ptr<StmtAncestorASTVisitor> ParentFinder;
412 StmtGeneratedVarNameMap GeneratedDecls;
413 ReplacedVarsMap ReplacedVars;
414};
415
416/// Create names for generated variables within a particular statement.
417///
418/// VariableNamer uses a DeclContext as a reference point, checking for any
419/// conflicting declarations higher up in the context or within SourceStmt.
420/// It creates a variable name using hints from a source container and the old
421/// index, if they exist.
423public:
424 // Supported naming styles.
431
433 const StmtParentMap *ReverseAST, const Stmt *SourceStmt,
434 const VarDecl *OldIndex, const ValueDecl *TheContainer,
435 const ASTContext *Context, NamingStyle Style)
436 : GeneratedDecls(GeneratedDecls), ReverseAST(ReverseAST),
437 SourceStmt(SourceStmt), OldIndex(OldIndex), TheContainer(TheContainer),
438 Context(Context), Style(Style) {}
439
440 /// Generate a new index name.
441 ///
442 /// Generates the name to be used for an inserted iterator. It relies on
443 /// declarationExists() to determine that there are no naming conflicts, and
444 /// tries to use some hints from the container name and the old index name.
445 std::string createIndexName();
446
447private:
448 StmtGeneratedVarNameMap *GeneratedDecls;
449 const StmtParentMap *ReverseAST;
450 const Stmt *SourceStmt;
451 const VarDecl *OldIndex;
452 const ValueDecl *TheContainer;
453 const ASTContext *Context;
454 const NamingStyle Style;
455
456 // Determine whether or not a declaration that would conflict with Symbol
457 // exists in an outer context or in any statement contained in SourceStmt.
458 bool declarationExists(StringRef Symbol);
459};
460
461} // namespace clang::tidy::modernize
462
463#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOPCONVERTUTILS_H
Class used to find the variables and member expressions on which an arbitrary expression depends.
void findExprComponents(const Expr *SourceExpr)
Find the components of an expression and place them in a ComponentVector.
const ComponentVector & getComponents()
Accessor for Components.
A class to encapsulate lowering of the tool's confidence level.
Level getLevel() const
Return the internal confidence level.
Confidence(Confidence::Level Level)
Initialize confidence level.
void lowerTo(Confidence::Level Level)
Lower the internal confidence level to Level, but do not raise it.
Class used to determine if any declarations used in a Stmt would conflict with a particular identifie...
bool findUsages(const Stmt *Body)
Attempts to find any usages of variables name Name in Body, returning true when it is used in Body.
DeclFinderASTVisitor(const StringRef &Name, const StmtGeneratedVarNameMap *GeneratedDecls)
Class used to determine if an expression is dependent on a variable declared inside of the loop where...
bool dependsOnInsideVariable(const Stmt *Body)
Run the analysis on Body, and return true iff the expression depends on some variable declared within...
DependencyFinderASTVisitor(const StmtParentMap *StmtParents, const DeclParentMap *DeclParents, const ReplacedVarsMap *ReplacedVars, const Stmt *ContainingStmt)
Discover usages of expressions consisting of index or iterator access.
const UsageResult & getUsages() const
Accessor for Usages.
bool aliasFromForInit() const
Indicates if the alias declaration came from the init clause of a nested for loop.
const DeclStmt * getAliasDecl() const
Returns the statement declaring the variable created as an alias for the loop element,...
ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar, const VarDecl *EndVar, const Expr *ContainerExpr, const Expr *ArrayBoundExpr, bool ContainerNeedsDereference)
bool aliasUseRequired() const
Indicates if the alias declaration was in a place where it cannot simply be removed but rather replac...
bool findAndVerifyUsages(const Stmt *Body)
Finds all uses of IndexVar in Body, placing all usages in Usages, and returns true if IndexVar was on...
Confidence::Level getConfidenceLevel() const
Accessor for ConfidenceLevel.
void addUsage(const Usage &U)
Adds the Usage if it was not added before.
void addComponents(const ComponentVector &Components)
Add a set of components that we should consider relevant to the container.
const Expr * getContainerIndexed() const
Get the container indexed by IndexVar, if any.
Class used build the reverse AST properties needed to detect name conflicts and free variables.
void gatherAncestors(ASTContext &Ctx)
Run the analysis on the AST.
const DeclParentMap & getDeclToParentStmtMap()
Accessor for DeclParents.
const StmtParentMap & getStmtToParentStmtMap()
Accessor for StmtAncestors.
VariableNamer(StmtGeneratedVarNameMap *GeneratedDecls, const StmtParentMap *ReverseAST, const Stmt *SourceStmt, const VarDecl *OldIndex, const ValueDecl *TheContainer, const ASTContext *Context, NamingStyle Style)
std::string createIndexName()
Generate a new index name.
SmallVector< const Expr *, 16 > ComponentVector
A vector used to store the AST subtrees of an Expr.
llvm::DenseMap< const Stmt *, const Stmt * > StmtParentMap
A map used to walk the AST in reverse: maps child Stmt to parent Stmt.
const DeclRefExpr * getDeclRef(const Expr *E)
Returns the DeclRefExpr represented by E, or NULL if there isn't one.
bool areSameVariable(const ValueDecl *First, const ValueDecl *Second)
Returns true when two ValueDecls are the same variable.
bool areSameExpr(const ASTContext *Context, const Expr *First, const Expr *Second)
Returns true when two Exprs are equivalent.
const Expr * digThroughConstructorsConversions(const Expr *E)
Look through conversion/copy constructors and member functions to find the explicit initialization ex...
llvm::DenseMap< const VarDecl *, const DeclStmt * > DeclParentMap
A map used to walk the AST in reverse: maps VarDecl to the to parent DeclStmt.
SmallVector< Usage, 8 > UsageResult
llvm::DenseMap< const ForStmt *, const VarDecl * > ReplacedVarsMap
A map used to track which variables have been removed by a refactoring pass.
llvm::DenseMap< const Stmt *, std::string > StmtGeneratedVarNameMap
A map used to remember the variable names generated in a Stmt.
TUTrackingInfo()
Reset and initialize per-TU tracking information.
StmtGeneratedVarNameMap & getGeneratedDecls()
StmtAncestorASTVisitor & getParentFinder()
The information needed to describe a valid convertible usage of an array index or iterator.
Usage(const Expr *E, UsageKind Kind, SourceRange Range)