blob: 1b6f59c8573d59603b1fd3619074a5b3c87feaa7 [file] [log] [blame]
Edwin Vanedde168b2013-01-04 18:25:18 +00001//===-- LoopConvert/LoopMatchers.h - Matchers for for loops -----*- 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/// \file
11/// \brief This file contains definitions of the matchers for use in migrating
12/// C++ for loops.
13///
14//===----------------------------------------------------------------------===//
15#include "LoopMatchers.h"
16
17using namespace clang::ast_matchers;
18using namespace clang;
19
20const char LoopName[] = "forLoop";
21const char ConditionBoundName[] = "conditionBound";
22const char ConditionVarName[] = "conditionVar";
23const char IncrementVarName[] = "incrementVar";
24const char InitVarName[] = "initVar";
25const char EndCallName[] = "endCall";
26const char ConditionEndVarName[] = "conditionEndVar";
27const char EndVarName[] = "endVar";
28
29// shared matchers
30static const TypeMatcher AnyType = anything();
31
32static const StatementMatcher IntegerComparisonMatcher =
33 expr(ignoringParenImpCasts(declRefExpr(to(
34 varDecl(hasType(isInteger())).bind(ConditionVarName)))));
35
36static const DeclarationMatcher InitToZeroMatcher =
37 varDecl(hasInitializer(ignoringParenImpCasts(
38 integerLiteral(equals(0))))).bind(InitVarName);
39
40static const StatementMatcher IncrementVarMatcher =
41 declRefExpr(to(
42 varDecl(hasType(isInteger())).bind(IncrementVarName)));
43
44// FIXME: How best to document complicated matcher expressions? They're fairly
45// self-documenting...but there may be some unintuitive parts.
46
47/// \brief The matcher for loops over arrays.
48///
49/// In this general example, assuming 'j' and 'k' are of integral type:
50/// \code
51/// for (int i = 0; j < 3 + 2; ++k) { ... }
52/// \endcode
53/// The following string identifers are bound to the parts of the AST:
54/// ConditionVarName: 'j' (as a VarDecl)
55/// ConditionBoundName: '3 + 2' (as an Expr)
56/// InitVarName: 'i' (as a VarDecl)
57/// IncrementVarName: 'k' (as a VarDecl)
58/// LoopName: The entire for loop (as a ForStmt)
59///
60/// Client code will need to make sure that:
61/// - The three index variables identified by the matcher are the same
62/// VarDecl.
63/// - The index variable is only used as an array index.
64/// - All arrays indexed by the loop are the same.
65StatementMatcher makeArrayLoopMatcher() {
66 StatementMatcher ArrayBoundMatcher =
67 expr(hasType(isInteger())).bind(ConditionBoundName);
68
69 return forStmt(
70 hasLoopInit(declStmt(hasSingleDecl(InitToZeroMatcher))),
71 hasCondition(anyOf(binaryOperator(hasOperatorName("<"),
72 hasLHS(IntegerComparisonMatcher),
73 hasRHS(ArrayBoundMatcher)),
74 binaryOperator(hasOperatorName(">"),
75 hasLHS(ArrayBoundMatcher),
76 hasRHS(IntegerComparisonMatcher)))),
77 hasIncrement(unaryOperator(hasOperatorName("++"),
78 hasUnaryOperand(IncrementVarMatcher))))
79 .bind(LoopName);
80}
81
82/// \brief The matcher used for iterator-based for loops.
83///
84/// This matcher is more flexible than array-based loops. It will match
85/// catch loops of the following textual forms (regardless of whether the
86/// iterator type is actually a pointer type or a class type):
87///
88/// Assuming f, g, and h are of type containerType::iterator,
89/// \code
90/// for (containerType::iterator it = container.begin(),
91/// e = createIterator(); f != g; ++h) { ... }
92/// for (containerType::iterator it = container.begin();
93/// f != anotherContainer.end(); ++h) { ... }
94/// \endcode
95/// The following string identifiers are bound to the parts of the AST:
96/// InitVarName: 'it' (as a VarDecl)
97/// ConditionVarName: 'f' (as a VarDecl)
98/// LoopName: The entire for loop (as a ForStmt)
99/// In the first example only:
100/// EndVarName: 'e' (as a VarDecl)
101/// ConditionEndVarName: 'g' (as a VarDecl)
102/// In the second example only:
103/// EndCallName: 'container.end()' (as a CXXMemberCallExpr)
104///
105/// Client code will need to make sure that:
106/// - The iterator variables 'it', 'f', and 'h' are the same
107/// - The two containers on which 'begin' and 'end' are called are the same
108/// - If the end iterator variable 'g' is defined, it is the same as 'f'
109StatementMatcher makeIteratorLoopMatcher() {
110 StatementMatcher BeginCallMatcher =
111 memberCallExpr(argumentCountIs(0), callee(methodDecl(hasName("begin"))));
112
113 DeclarationMatcher InitDeclMatcher =
114 varDecl(hasInitializer(anything())).bind(InitVarName);
115
116 DeclarationMatcher EndDeclMatcher =
117 varDecl(hasInitializer(anything())).bind(EndVarName);
118
119 StatementMatcher EndCallMatcher =
120 memberCallExpr(argumentCountIs(0), callee(methodDecl(hasName("end"))));
121
122 StatementMatcher IteratorBoundMatcher =
123 expr(anyOf(ignoringParenImpCasts(declRefExpr(to(
124 varDecl().bind(ConditionEndVarName)))),
125 ignoringParenImpCasts(
126 expr(EndCallMatcher).bind(EndCallName)),
127 materializeTemporaryExpr(ignoringParenImpCasts(
128 expr(EndCallMatcher).bind(EndCallName)))));
129
130 StatementMatcher IteratorComparisonMatcher =
131 expr(ignoringParenImpCasts(declRefExpr(to(
132 varDecl().bind(ConditionVarName)))));
133
134 StatementMatcher OverloadedNEQMatcher = operatorCallExpr(
135 hasOverloadedOperatorName("!="),
136 argumentCountIs(2),
137 hasArgument(0, IteratorComparisonMatcher),
138 hasArgument(1, IteratorBoundMatcher));
139
140 return forStmt(
141 hasLoopInit(anyOf(
142 declStmt(declCountIs(2),
143 containsDeclaration(0, InitDeclMatcher),
144 containsDeclaration(1, EndDeclMatcher)),
145 declStmt(hasSingleDecl(InitDeclMatcher)))),
146 hasCondition(anyOf(
147 binaryOperator(hasOperatorName("!="),
148 hasLHS(IteratorComparisonMatcher),
149 hasRHS(IteratorBoundMatcher)),
150 binaryOperator(hasOperatorName("!="),
151 hasLHS(IteratorBoundMatcher),
152 hasRHS(IteratorComparisonMatcher)),
153 OverloadedNEQMatcher)),
154 hasIncrement(anyOf(
155 unaryOperator(hasOperatorName("++"),
156 hasUnaryOperand(declRefExpr(to(
157 varDecl(hasType(pointsTo(AnyType)))
158 .bind(IncrementVarName))))),
159 operatorCallExpr(
160 hasOverloadedOperatorName("++"),
161 hasArgument(0, declRefExpr(to(
162 varDecl().bind(IncrementVarName))))))))
163 .bind(LoopName);
164}
165
166/// \brief The matcher used for array-like containers (pseudoarrays).
167///
168/// This matcher is more flexible than array-based loops. It will match
169/// loops of the following textual forms (regardless of whether the
170/// iterator type is actually a pointer type or a class type):
171///
172/// Assuming f, g, and h are of type containerType::iterator,
173/// \code
174/// for (int i = 0, j = container.size(); f < g; ++h) { ... }
175/// for (int i = 0; f < container.size(); ++h) { ... }
176/// \endcode
177/// The following string identifiers are bound to the parts of the AST:
178/// InitVarName: 'i' (as a VarDecl)
179/// ConditionVarName: 'f' (as a VarDecl)
180/// LoopName: The entire for loop (as a ForStmt)
181/// In the first example only:
182/// EndVarName: 'j' (as a VarDecl)
183/// ConditionEndVarName: 'g' (as a VarDecl)
184/// In the second example only:
185/// EndCallName: 'container.size()' (as a CXXMemberCallExpr)
186///
187/// Client code will need to make sure that:
188/// - The index variables 'i', 'f', and 'h' are the same
189/// - The containers on which 'size()' is called is the container indexed
190/// - The index variable is only used in overloaded operator[] or
191/// container.at()
192/// - If the end iterator variable 'g' is defined, it is the same as 'j'
193/// - The container's iterators would not be invalidated during the loop
194StatementMatcher makePseudoArrayLoopMatcher() {
195 StatementMatcher SizeCallMatcher =
196 memberCallExpr(argumentCountIs(0),
197 callee(methodDecl(anyOf(hasName("size"),
198 hasName("length")))));
199
200 StatementMatcher EndInitMatcher =
201 expr(anyOf(
202 ignoringParenImpCasts(expr(SizeCallMatcher).bind(EndCallName)),
203 explicitCastExpr(hasSourceExpression(ignoringParenImpCasts(
204 expr(SizeCallMatcher).bind(EndCallName))))));
205
206 DeclarationMatcher EndDeclMatcher =
207 varDecl(hasInitializer(EndInitMatcher)).bind(EndVarName);
208
209 StatementMatcher IndexBoundMatcher =
210 expr(anyOf(
211 ignoringParenImpCasts(declRefExpr(to(
212 varDecl(hasType(isInteger())).bind(ConditionEndVarName)))),
213 EndInitMatcher));
214
215 return forStmt(
216 hasLoopInit(anyOf(
217 declStmt(declCountIs(2),
218 containsDeclaration(0, InitToZeroMatcher),
219 containsDeclaration(1, EndDeclMatcher)),
220 declStmt(hasSingleDecl(InitToZeroMatcher)))),
221 hasCondition(anyOf(
222 binaryOperator(hasOperatorName("<"),
223 hasLHS(IntegerComparisonMatcher),
224 hasRHS(IndexBoundMatcher)),
225 binaryOperator(hasOperatorName(">"),
226 hasLHS(IndexBoundMatcher),
227 hasRHS(IntegerComparisonMatcher)))),
228 hasIncrement(unaryOperator(
229 hasOperatorName("++"),
230 hasUnaryOperand(IncrementVarMatcher))))
231 .bind(LoopName);
232}