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(ASTContext *Context, const Expr *First, const Expr *Second);
272const DeclRefExpr *getDeclRef(const Expr *E);
273bool areSameVariable(const ValueDecl *First, const ValueDecl *Second);
274
275/// Discover usages of expressions consisting of index or iterator
276/// access.
277///
278/// Given an index variable, recursively crawls a for loop to discover if the
279/// index variable is used in a way consistent with range-based for loop access.
281 : public RecursiveASTVisitor<ForLoopIndexUseVisitor> {
282public:
283 ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar,
284 const VarDecl *EndVar, const Expr *ContainerExpr,
285 const Expr *ArrayBoundExpr,
286 bool ContainerNeedsDereference);
287
288 /// Finds all uses of IndexVar in Body, placing all usages in Usages,
289 /// and returns true if IndexVar was only used in a way consistent with a
290 /// range-based for loop.
291 ///
292 /// The general strategy is to reject any DeclRefExprs referencing IndexVar,
293 /// with the exception of certain acceptable patterns.
294 /// For arrays, the DeclRefExpr for IndexVar must appear as the index of an
295 /// ArraySubscriptExpression. Iterator-based loops may dereference
296 /// IndexVar or call methods through operator-> (builtin or overloaded).
297 /// Array-like containers may use IndexVar as a parameter to the at() member
298 /// function and in overloaded operator[].
299 bool findAndVerifyUsages(const Stmt *Body);
300
301 /// Add a set of components that we should consider relevant to the
302 /// container.
303 void addComponents(const ComponentVector &Components);
304
305 /// Accessor for Usages.
306 const UsageResult &getUsages() const { return Usages; }
307
308 /// Adds the Usage if it was not added before.
309 void addUsage(const Usage &U);
310
311 /// Get the container indexed by IndexVar, if any.
312 const Expr *getContainerIndexed() const { return ContainerExpr; }
313
314 /// Returns the statement declaring the variable created as an alias
315 /// for the loop element, if any.
316 const DeclStmt *getAliasDecl() const { return AliasDecl; }
317
318 /// Accessor for ConfidenceLevel.
320 return ConfidenceLevel.getLevel();
321 }
322
323 /// Indicates if the alias declaration was in a place where it cannot
324 /// simply be removed but rather replaced with a use of the alias variable.
325 /// For example, variables declared in the condition of an if, switch, or for
326 /// stmt.
327 bool aliasUseRequired() const { return ReplaceWithAliasUse; }
328
329 /// Indicates if the alias declaration came from the init clause of a
330 /// nested for loop. SourceRanges provided by Clang for DeclStmts in this
331 /// case need to be adjusted.
332 bool aliasFromForInit() const { return AliasFromForInit; }
333
334private:
335 /// Typedef used in CRTP functions.
336 using VisitorBase = RecursiveASTVisitor<ForLoopIndexUseVisitor>;
337 friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>;
338
339 /// Overriden methods for RecursiveASTVisitor's traversal.
340 bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
341 bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
342 bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
343 bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
344 Expr *Init);
345 bool TraverseMemberExpr(MemberExpr *Member);
346 bool TraverseUnaryOperator(UnaryOperator *Uop);
347 bool VisitDeclRefExpr(DeclRefExpr *E);
348 bool VisitDeclStmt(DeclStmt *S);
349 bool TraverseStmt(Stmt *S);
350
351 bool traverseStmtImpl(Stmt *S);
352
353 /// Add an expression to the list of expressions on which the container
354 /// expression depends.
355 void addComponent(const Expr *E);
356
357 // Input member variables:
358 ASTContext *Context;
359 /// The index variable's VarDecl.
360 const VarDecl *IndexVar;
361 /// The loop's 'end' variable, which cannot be mentioned at all.
362 const VarDecl *EndVar;
363 /// The Expr which refers to the container.
364 const Expr *ContainerExpr;
365 /// The Expr which refers to the terminating condition for array-based loops.
366 const Expr *ArrayBoundExpr;
367 bool ContainerNeedsDereference;
368
369 // Output member variables:
370 /// A container which holds all usages of IndexVar as the index of
371 /// ArraySubscriptExpressions.
372 UsageResult Usages;
373 llvm::SmallSet<SourceLocation, 8> UsageLocations;
374 bool OnlyUsedAsIndex = true;
375 /// The DeclStmt for an alias to the container element.
376 const DeclStmt *AliasDecl = nullptr;
377 Confidence ConfidenceLevel;
378 /// A list of expressions on which ContainerExpr depends.
379 ///
380 /// If any of these expressions are encountered outside of an acceptable usage
381 /// of the loop element, lower our confidence level.
383 DependentExprs;
384
385 /// The parent-in-waiting. Will become the real parent once we traverse down
386 /// one level in the AST.
387 const Stmt *NextStmtParent = nullptr;
388 /// The actual parent of a node when Visit*() calls are made. Only the
389 /// parentage of DeclStmt's to possible iteration/selection statements is of
390 /// importance.
391 const Stmt *CurrStmtParent = nullptr;
392
393 /// \see aliasUseRequired().
394 bool ReplaceWithAliasUse = false;
395 /// \see aliasFromForInit().
396 bool AliasFromForInit = false;
397};
398
400 /// Reset and initialize per-TU tracking information.
401 ///
402 /// Must be called before using container accessors.
403 TUTrackingInfo() : ParentFinder(new StmtAncestorASTVisitor) {}
404
405 StmtAncestorASTVisitor &getParentFinder() { return *ParentFinder; }
406 StmtGeneratedVarNameMap &getGeneratedDecls() { return GeneratedDecls; }
407 ReplacedVarsMap &getReplacedVars() { return ReplacedVars; }
408
409private:
410 std::unique_ptr<StmtAncestorASTVisitor> ParentFinder;
411 StmtGeneratedVarNameMap GeneratedDecls;
412 ReplacedVarsMap ReplacedVars;
413};
414
415/// Create names for generated variables within a particular statement.
416///
417/// VariableNamer uses a DeclContext as a reference point, checking for any
418/// conflicting declarations higher up in the context or within SourceStmt.
419/// It creates a variable name using hints from a source container and the old
420/// index, if they exist.
422public:
423 // Supported naming styles.
430
432 const StmtParentMap *ReverseAST, const Stmt *SourceStmt,
433 const VarDecl *OldIndex, const ValueDecl *TheContainer,
434 const ASTContext *Context, NamingStyle Style)
435 : GeneratedDecls(GeneratedDecls), ReverseAST(ReverseAST),
436 SourceStmt(SourceStmt), OldIndex(OldIndex), TheContainer(TheContainer),
437 Context(Context), Style(Style) {}
438
439 /// Generate a new index name.
440 ///
441 /// Generates the name to be used for an inserted iterator. It relies on
442 /// declarationExists() to determine that there are no naming conflicts, and
443 /// tries to use some hints from the container name and the old index name.
444 std::string createIndexName();
445
446private:
447 StmtGeneratedVarNameMap *GeneratedDecls;
448 const StmtParentMap *ReverseAST;
449 const Stmt *SourceStmt;
450 const VarDecl *OldIndex;
451 const ValueDecl *TheContainer;
452 const ASTContext *Context;
453 const NamingStyle Style;
454
455 // Determine whether or not a declaration that would conflict with Symbol
456 // exists in an outer context or in any statement contained in SourceStmt.
457 bool declarationExists(StringRef Symbol);
458};
459
460} // namespace clang::tidy::modernize
461
462#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.
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
bool areSameExpr(ASTContext *Context, const Expr *First, const Expr *Second)
Returns true when two Exprs are equivalent.
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)