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