blob: f8b70565dc79a0f329f92cbfb5a4b686d736b9c5 [file] [log] [blame]
Shuai Wange9192f82018-09-11 21:13:20 +00001//===---------- ExprMutationAnalyzerTest.cpp ------------------------------===//
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#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
13#include "clang/Tooling/Tooling.h"
14#include "gmock/gmock.h"
15#include "gtest/gtest.h"
16#include <cctype>
17
18namespace clang {
19
20using namespace clang::ast_matchers;
21using ::testing::ElementsAre;
22using ::testing::IsEmpty;
23using ::testing::ResultOf;
24using ::testing::StartsWith;
25using ::testing::Values;
26
27namespace {
28
29using ExprMatcher = internal::Matcher<Expr>;
30using StmtMatcher = internal::Matcher<Stmt>;
31
32ExprMatcher declRefTo(StringRef Name) {
33 return declRefExpr(to(namedDecl(hasName(Name))));
34}
35
36StmtMatcher withEnclosingCompound(ExprMatcher Matcher) {
37 return expr(Matcher, hasAncestor(compoundStmt().bind("stmt"))).bind("expr");
38}
39
40bool isMutated(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
41 const auto *const S = selectFirst<Stmt>("stmt", Results);
42 const auto *const E = selectFirst<Expr>("expr", Results);
43 return ExprMutationAnalyzer(*S, AST->getASTContext()).isMutated(E);
44}
45
46SmallVector<std::string, 1>
47mutatedBy(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
48 const auto *const S = selectFirst<Stmt>("stmt", Results);
49 SmallVector<std::string, 1> Chain;
50 ExprMutationAnalyzer Analyzer(*S, AST->getASTContext());
51 for (const auto *E = selectFirst<Expr>("expr", Results); E != nullptr;) {
52 const Stmt *By = Analyzer.findMutation(E);
53 std::string buffer;
54 llvm::raw_string_ostream stream(buffer);
55 By->printPretty(stream, nullptr, AST->getASTContext().getPrintingPolicy());
56 Chain.push_back(StringRef(stream.str()).trim().str());
57 E = dyn_cast<DeclRefExpr>(By);
58 }
59 return Chain;
60}
61
62std::string removeSpace(std::string s) {
63 s.erase(std::remove_if(s.begin(), s.end(),
64 [](char c) { return std::isspace(c); }),
65 s.end());
66 return s;
67}
68
69} // namespace
70
71TEST(ExprMutationAnalyzerTest, Trivial) {
72 const auto AST = tooling::buildASTFromCode("void f() { int x; x; }");
73 const auto Results =
74 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
75 EXPECT_FALSE(isMutated(Results, AST.get()));
76}
77
78class AssignmentTest : public ::testing::TestWithParam<std::string> {};
79
80TEST_P(AssignmentTest, AssignmentModifies) {
81 const std::string ModExpr = "x " + GetParam() + " 10";
82 const auto AST =
83 tooling::buildASTFromCode("void f() { int x; " + ModExpr + "; }");
84 const auto Results =
85 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
86 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
87}
88
89INSTANTIATE_TEST_CASE_P(AllAssignmentOperators, AssignmentTest,
90 Values("=", "+=", "-=", "*=", "/=", "%=", "&=", "|=",
91 "^=", "<<=", ">>="), );
92
93class IncDecTest : public ::testing::TestWithParam<std::string> {};
94
95TEST_P(IncDecTest, IncDecModifies) {
96 const std::string ModExpr = GetParam();
97 const auto AST =
98 tooling::buildASTFromCode("void f() { int x; " + ModExpr + "; }");
99 const auto Results =
100 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
101 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
102}
103
104INSTANTIATE_TEST_CASE_P(AllIncDecOperators, IncDecTest,
105 Values("++x", "--x", "x++", "x--"), );
106
107TEST(ExprMutationAnalyzerTest, NonConstMemberFunc) {
108 const auto AST = tooling::buildASTFromCode(
109 "void f() { struct Foo { void mf(); }; Foo x; x.mf(); }");
110 const auto Results =
111 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
112 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
113}
114
115TEST(ExprMutationAnalyzerTest, AssumedNonConstMemberFunc) {
116 auto AST = tooling::buildASTFromCodeWithArgs(
117 "struct X { template <class T> void mf(); };"
118 "template <class T> void f() { X x; x.mf<T>(); }",
119 {"-fno-delayed-template-parsing"});
120 auto Results =
121 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
122 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf<T>()"));
123
124 AST = tooling::buildASTFromCodeWithArgs(
125 "template <class T> void f() { T x; x.mf(); }",
126 {"-fno-delayed-template-parsing"});
127 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
128 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
129
130 AST = tooling::buildASTFromCodeWithArgs(
131 "template <class T> struct X;"
132 "template <class T> void f() { X<T> x; x.mf(); }",
133 {"-fno-delayed-template-parsing"});
134 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
135 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
136}
137
138TEST(ExprMutationAnalyzerTest, ConstMemberFunc) {
139 const auto AST = tooling::buildASTFromCode(
140 "void f() { struct Foo { void mf() const; }; Foo x; x.mf(); }");
141 const auto Results =
142 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
143 EXPECT_FALSE(isMutated(Results, AST.get()));
144}
145
146TEST(ExprMutationAnalyzerTest, NonConstOperator) {
147 const auto AST = tooling::buildASTFromCode(
148 "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }");
149 const auto Results =
150 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
151 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10"));
152}
153
154TEST(ExprMutationAnalyzerTest, ConstOperator) {
155 const auto AST = tooling::buildASTFromCode(
156 "void f() { struct Foo { int operator()() const; }; Foo x; x(); }");
157 const auto Results =
158 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
159 EXPECT_FALSE(isMutated(Results, AST.get()));
160}
161
162TEST(ExprMutationAnalyzerTest, ByValueArgument) {
163 auto AST =
164 tooling::buildASTFromCode("void g(int); void f() { int x; g(x); }");
165 auto Results =
166 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
167 EXPECT_FALSE(isMutated(Results, AST.get()));
168
169 AST = tooling::buildASTFromCode("void g(int*); void f() { int* x; g(x); }");
170 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
171 EXPECT_FALSE(isMutated(Results, AST.get()));
172
173 AST = tooling::buildASTFromCode("typedef int* IntPtr;"
174 "void g(IntPtr); void f() { int* x; g(x); }");
175 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
176 EXPECT_FALSE(isMutated(Results, AST.get()));
177
178 AST = tooling::buildASTFromCode(
179 "void f() { struct A {}; A operator+(A, int); A x; x + 1; }");
180 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
181 EXPECT_FALSE(isMutated(Results, AST.get()));
182
183 AST = tooling::buildASTFromCode(
184 "void f() { struct A { A(int); }; int x; A y(x); }");
185 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
186 EXPECT_FALSE(isMutated(Results, AST.get()));
187
188 AST = tooling::buildASTFromCode(
189 "void f() { struct A { A(); A(A); }; A x; A y(x); }");
190 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
191 EXPECT_FALSE(isMutated(Results, AST.get()));
192}
193
194TEST(ExprMutationAnalyzerTest, ByConstValueArgument) {
195 auto AST =
196 tooling::buildASTFromCode("void g(const int); void f() { int x; g(x); }");
197 auto Results =
198 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
199 EXPECT_FALSE(isMutated(Results, AST.get()));
200
201 AST = tooling::buildASTFromCode(
202 "void g(int* const); void f() { int* x; g(x); }");
203 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
204 EXPECT_FALSE(isMutated(Results, AST.get()));
205
206 AST =
207 tooling::buildASTFromCode("typedef int* const CIntPtr;"
208 "void g(CIntPtr); void f() { int* x; g(x); }");
209 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
210 EXPECT_FALSE(isMutated(Results, AST.get()));
211
212 AST = tooling::buildASTFromCode(
213 "void f() { struct A {}; A operator+(const A, int); A x; x + 1; }");
214 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
215 EXPECT_FALSE(isMutated(Results, AST.get()));
216
217 AST = tooling::buildASTFromCode(
218 "void f() { struct A { A(const int); }; int x; A y(x); }");
219 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
220 EXPECT_FALSE(isMutated(Results, AST.get()));
221
222 AST = tooling::buildASTFromCode(
223 "void f() { struct A { A(); A(const A); }; A x; A y(x); }");
224 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
225 EXPECT_FALSE(isMutated(Results, AST.get()));
226}
227
228TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) {
229 auto AST =
230 tooling::buildASTFromCode("void g(int&); void f() { int x; g(x); }");
231 auto Results =
232 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
233 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
234
235 AST = tooling::buildASTFromCode("typedef int& IntRef;"
236 "void g(IntRef); void f() { int x; g(x); }");
237 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
238 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
239
240 AST =
241 tooling::buildASTFromCode("template <class T> using TRef = T&;"
242 "void g(TRef<int>); void f() { int x; g(x); }");
243 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
244 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
245
246 AST = tooling::buildASTFromCode(
247 "template <class T> struct identity { using type = T; };"
248 "template <class T, class U = T&> void g(typename identity<U>::type);"
249 "void f() { int x; g<int>(x); }");
250 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
251 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g<int>(x)"));
252
253 AST =
254 tooling::buildASTFromCode("typedef int* IntPtr;"
255 "void g(IntPtr&); void f() { int* x; g(x); }");
256 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
257 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
258
259 AST = tooling::buildASTFromCode(
260 "typedef int* IntPtr; typedef IntPtr& IntPtrRef;"
261 "void g(IntPtrRef); void f() { int* x; g(x); }");
262 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
263 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
264
265 AST = tooling::buildASTFromCode(
266 "void f() { struct A {}; A operator+(A&, int); A x; x + 1; }");
267 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
268 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1"));
269
270 AST = tooling::buildASTFromCode(
271 "void f() { struct A { A(int&); }; int x; A y(x); }");
272 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
273 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
274
275 AST = tooling::buildASTFromCode(
276 "void f() { struct A { A(); A(A&); }; A x; A y(x); }");
277 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
278 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
279}
280
281TEST(ExprMutationAnalyzerTest, ByConstRefArgument) {
282 auto AST = tooling::buildASTFromCode(
283 "void g(const int&); void f() { int x; g(x); }");
284 auto Results =
285 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
286 EXPECT_FALSE(isMutated(Results, AST.get()));
287
288 AST = tooling::buildASTFromCode("typedef const int& CIntRef;"
289 "void g(CIntRef); void f() { int x; g(x); }");
290 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
291 EXPECT_FALSE(isMutated(Results, AST.get()));
292
293 AST = tooling::buildASTFromCode(
294 "template <class T> using CTRef = const T&;"
295 "void g(CTRef<int>); void f() { int x; g(x); }");
296 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
297 EXPECT_FALSE(isMutated(Results, AST.get()));
298
299 AST = tooling::buildASTFromCode(
300 "template <class T> struct identity { using type = T; };"
301 "template <class T, class U = const T&>"
302 "void g(typename identity<U>::type);"
303 "void f() { int x; g<int>(x); }");
304 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
305 EXPECT_FALSE(isMutated(Results, AST.get()));
306
307 AST = tooling::buildASTFromCode(
308 "void f() { struct A {}; A operator+(const A&, int); A x; x + 1; }");
309 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
310 EXPECT_FALSE(isMutated(Results, AST.get()));
311
312 AST = tooling::buildASTFromCode(
313 "void f() { struct A { A(const int&); }; int x; A y(x); }");
314 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
315 EXPECT_FALSE(isMutated(Results, AST.get()));
316
317 AST = tooling::buildASTFromCode(
318 "void f() { struct A { A(); A(const A&); }; A x; A y(x); }");
319 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
320 EXPECT_FALSE(isMutated(Results, AST.get()));
321}
322
323TEST(ExprMutationAnalyzerTest, ByNonConstRRefArgument) {
324 auto AST = tooling::buildASTFromCode(
325 "void g(int&&); void f() { int x; g(static_cast<int &&>(x)); }");
326 auto Results =
327 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
328 EXPECT_THAT(mutatedBy(Results, AST.get()),
329 ElementsAre("g(static_cast<int &&>(x))"));
330
331 AST = tooling::buildASTFromCode(
332 "void f() { struct A {}; A operator+(A&&, int); "
333 "A x; static_cast<A &&>(x) + 1; }");
334 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
335 EXPECT_THAT(mutatedBy(Results, AST.get()),
336 ElementsAre("static_cast<A &&>(x) + 1"));
337
338 AST = tooling::buildASTFromCode("void f() { struct A { A(int&&); }; "
339 "int x; A y(static_cast<int &&>(x)); }");
340 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
341 EXPECT_THAT(mutatedBy(Results, AST.get()),
342 ElementsAre("static_cast<int &&>(x)"));
343
344 AST = tooling::buildASTFromCode("void f() { struct A { A(); A(A&&); }; "
345 "A x; A y(static_cast<A &&>(x)); }");
346 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
347 EXPECT_THAT(mutatedBy(Results, AST.get()),
348 ElementsAre("static_cast<A &&>(x)"));
349}
350
351TEST(ExprMutationAnalyzerTest, ByConstRRefArgument) {
352 auto AST = tooling::buildASTFromCode(
353 "void g(const int&&); void f() { int x; g(static_cast<int&&>(x)); }");
354 auto Results =
355 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
356 EXPECT_FALSE(isMutated(Results, AST.get()));
357
358 AST = tooling::buildASTFromCode(
359 "void f() { struct A {}; A operator+(const A&&, int); "
360 "A x; static_cast<A&&>(x) + 1; }");
361 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
362 EXPECT_FALSE(isMutated(Results, AST.get()));
363
364 AST = tooling::buildASTFromCode("void f() { struct A { A(const int&&); }; "
365 "int x; A y(static_cast<int&&>(x)); }");
366 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
367 EXPECT_FALSE(isMutated(Results, AST.get()));
368
369 AST = tooling::buildASTFromCode("void f() { struct A { A(); A(const A&&); }; "
370 "A x; A y(static_cast<A&&>(x)); }");
371 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
372 EXPECT_FALSE(isMutated(Results, AST.get()));
373}
374
375TEST(ExprMutationAnalyzerTest, Move) {
376 // Technically almost the same as ByNonConstRRefArgument, just double checking
377 const auto AST = tooling::buildASTFromCode(
378 "namespace std {"
379 "template<class T> struct remove_reference { typedef T type; };"
380 "template<class T> struct remove_reference<T&> { typedef T type; };"
381 "template<class T> struct remove_reference<T&&> { typedef T type; };"
382 "template<class T> typename std::remove_reference<T>::type&& "
383 "move(T&& t) noexcept; }"
384 "void f() { struct A {}; A x; std::move(x); }");
385 const auto Results =
386 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
387 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x)"));
388}
389
390TEST(ExprMutationAnalyzerTest, Forward) {
391 // Technically almost the same as ByNonConstRefArgument, just double checking
392 const auto AST = tooling::buildASTFromCode(
393 "namespace std {"
394 "template<class T> struct remove_reference { typedef T type; };"
395 "template<class T> struct remove_reference<T&> { typedef T type; };"
396 "template<class T> struct remove_reference<T&&> { typedef T type; };"
397 "template<class T> T&& "
398 "forward(typename std::remove_reference<T>::type&) noexcept;"
399 "template<class T> T&& "
400 "forward(typename std::remove_reference<T>::type&&) noexcept;"
401 "void f() { struct A {}; A x; std::forward<A &>(x); }");
402 const auto Results =
403 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
404 EXPECT_THAT(mutatedBy(Results, AST.get()),
405 ElementsAre("std::forward<A &>(x)"));
406}
407
408TEST(ExprMutationAnalyzerTest, CallUnresolved) {
409 auto AST = tooling::buildASTFromCodeWithArgs(
410 "template <class T> void f() { T x; g(x); }",
411 {"-fno-delayed-template-parsing"});
412 auto Results =
413 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
414 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
415
416 AST = tooling::buildASTFromCodeWithArgs(
417 "template <int N> void f() { char x[N]; g(x); }",
418 {"-fno-delayed-template-parsing"});
419 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
420 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
421
422 AST = tooling::buildASTFromCodeWithArgs(
423 "template <class T> void f(T t) { int x; g(t, x); }",
424 {"-fno-delayed-template-parsing"});
425 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
426 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(t, x)"));
427
428 AST = tooling::buildASTFromCodeWithArgs(
429 "template <class T> void f(T t) { int x; t.mf(x); }",
430 {"-fno-delayed-template-parsing"});
431 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
432 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("t.mf(x)"));
433
434 AST = tooling::buildASTFromCodeWithArgs(
435 "template <class T> struct S;"
436 "template <class T> void f() { S<T> s; int x; s.mf(x); }",
437 {"-fno-delayed-template-parsing"});
438 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
439 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)"));
440
441 AST = tooling::buildASTFromCodeWithArgs(
442 "struct S { template <class T> void mf(); };"
443 "template <class T> void f(S s) { int x; s.mf<T>(x); }",
444 {"-fno-delayed-template-parsing"});
445 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
446 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf<T>(x)"));
447
448 AST = tooling::buildASTFromCodeWithArgs("template <class F>"
449 "void g(F f) { int x; f(x); } ",
450 {"-fno-delayed-template-parsing"});
451 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
452 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f(x)"));
453
454 AST = tooling::buildASTFromCodeWithArgs(
455 "template <class T> void f() { int x; (void)T(x); }",
456 {"-fno-delayed-template-parsing"});
457 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
458 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("T(x)"));
459}
460
461TEST(ExprMutationAnalyzerTest, ReturnAsValue) {
462 auto AST = tooling::buildASTFromCode("int f() { int x; return x; }");
463 auto Results =
464 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
465 EXPECT_FALSE(isMutated(Results, AST.get()));
466
467 AST = tooling::buildASTFromCode("int* f() { int* x; return x; }");
468 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
469 EXPECT_FALSE(isMutated(Results, AST.get()));
470
471 AST = tooling::buildASTFromCode("typedef int* IntPtr;"
472 "IntPtr f() { int* x; return x; }");
473 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
474 EXPECT_FALSE(isMutated(Results, AST.get()));
475}
476
477TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) {
478 const auto AST = tooling::buildASTFromCode("int& f() { int x; return x; }");
479 const auto Results =
480 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
481 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;"));
482}
483
484TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) {
485 const auto AST =
486 tooling::buildASTFromCode("const int& f() { int x; return x; }");
487 const auto Results =
488 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
489 EXPECT_FALSE(isMutated(Results, AST.get()));
490}
491
492TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRRef) {
493 const auto AST = tooling::buildASTFromCode(
494 "int&& f() { int x; return static_cast<int &&>(x); }");
495 const auto Results =
496 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
497 EXPECT_THAT(mutatedBy(Results, AST.get()),
498 ElementsAre("return static_cast<int &&>(x);"));
499}
500
501TEST(ExprMutationAnalyzerTest, ReturnAsConstRRef) {
502 const auto AST = tooling::buildASTFromCode(
503 "const int&& f() { int x; return static_cast<int&&>(x); }");
504 const auto Results =
505 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
506 EXPECT_FALSE(isMutated(Results, AST.get()));
507}
508
509TEST(ExprMutationAnalyzerTest, TakeAddress) {
510 const auto AST =
511 tooling::buildASTFromCode("void g(int*); void f() { int x; g(&x); }");
512 const auto Results =
513 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
514 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x"));
515}
516
517TEST(ExprMutationAnalyzerTest, ArrayToPointerDecay) {
518 const auto AST =
519 tooling::buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }");
520 const auto Results =
521 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
522 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
523}
524
525TEST(ExprMutationAnalyzerTest, TemplateWithArrayToPointerDecay) {
526 const auto AST = tooling::buildASTFromCodeWithArgs(
527 "template <typename T> struct S { static constexpr int v = 8; };"
528 "template <> struct S<int> { static constexpr int v = 4; };"
529 "void g(char*);"
530 "template <typename T> void f() { char x[S<T>::v]; g(x); }"
531 "template <> void f<int>() { char y[S<int>::v]; g(y); }",
532 {"-fno-delayed-template-parsing"});
533 const auto ResultsX =
534 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
535 EXPECT_THAT(mutatedBy(ResultsX, AST.get()), ElementsAre("g(x)"));
536 const auto ResultsY =
537 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
538 EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y"));
539}
540
541TEST(ExprMutationAnalyzerTest, FollowRefModified) {
542 auto AST = tooling::buildASTFromCode(
543 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; "
544 "int& r3 = r2; r3 = 10; }");
545 auto Results =
546 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
547 EXPECT_THAT(mutatedBy(Results, AST.get()),
548 ElementsAre("r0", "r1", "r2", "r3", "r3 = 10"));
549
550 AST = tooling::buildASTFromCode(
551 "typedef int& IntRefX;"
552 "using IntRefY = int&;"
553 "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;"
554 "decltype((x)) r2 = r1; r2 = 10; }");
555 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
556 EXPECT_THAT(mutatedBy(Results, AST.get()),
557 ElementsAre("r0", "r1", "r2", "r2 = 10"));
558}
559
560TEST(ExprMutationAnalyzerTest, FollowRefNotModified) {
561 auto AST = tooling::buildASTFromCode(
562 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; "
563 "int& r3 = r2; int& r4 = r3; int& r5 = r4;}");
564 auto Results =
565 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
566 EXPECT_FALSE(isMutated(Results, AST.get()));
567
568 AST = tooling::buildASTFromCode(
569 "void f() { int x; int& r0 = x; const int& r1 = r0;}");
570 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
571 EXPECT_FALSE(isMutated(Results, AST.get()));
572
573 AST = tooling::buildASTFromCode(
574 "typedef const int& CIntRefX;"
575 "using CIntRefY = const int&;"
576 "void f() { int x; int& r0 = x; CIntRefX r1 = r0;"
577 "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}");
578 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
579 EXPECT_FALSE(isMutated(Results, AST.get()));
580}
581
582TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) {
583 const auto AST = tooling::buildASTFromCode(
584 "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }");
585 const auto Results =
586 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
587 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10"));
588}
589
590TEST(ExprMutationAnalyzerTest, FollowConditionalRefNotModified) {
591 const auto AST = tooling::buildASTFromCode(
592 "void f() { int x, y; bool b; int& r = b ? x : y; }");
593 const auto Results =
594 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
595 EXPECT_FALSE(isMutated(Results, AST.get()));
596}
597
598TEST(ExprMutationAnalyzerTest, ArrayElementModified) {
599 const auto AST =
600 tooling::buildASTFromCode("void f() { int x[2]; x[0] = 10; }");
601 const auto Results =
602 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
603 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10"));
604}
605
606TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) {
607 const auto AST = tooling::buildASTFromCode("void f() { int x[2]; x[0]; }");
608 const auto Results =
609 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
610 EXPECT_FALSE(isMutated(Results, AST.get()));
611}
612
613TEST(ExprMutationAnalyzerTest, NestedMemberModified) {
614 auto AST = tooling::buildASTFromCode(
615 "void f() { struct A { int vi; }; struct B { A va; }; "
616 "struct C { B vb; }; C x; x.vb.va.vi = 10; }");
617 auto Results =
618 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
619 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10"));
620
621 AST = tooling::buildASTFromCodeWithArgs(
622 "template <class T> void f() { T x; x.y.z = 10; }",
623 {"-fno-delayed-template-parsing"});
624 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
625 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10"));
626
627 AST = tooling::buildASTFromCodeWithArgs(
628 "template <class T> struct S;"
629 "template <class T> void f() { S<T> x; x.y.z = 10; }",
630 {"-fno-delayed-template-parsing"});
631 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
632 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10"));
633}
634
635TEST(ExprMutationAnalyzerTest, NestedMemberNotModified) {
636 auto AST = tooling::buildASTFromCode(
637 "void f() { struct A { int vi; }; struct B { A va; }; "
638 "struct C { B vb; }; C x; x.vb.va.vi; }");
639 auto Results =
640 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
641 EXPECT_FALSE(isMutated(Results, AST.get()));
642
643 AST = tooling::buildASTFromCodeWithArgs(
644 "template <class T> void f() { T x; x.y.z; }",
645 {"-fno-delayed-template-parsing"});
646 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
647 EXPECT_FALSE(isMutated(Results, AST.get()));
648
649 AST = tooling::buildASTFromCodeWithArgs(
650 "template <class T> struct S;"
651 "template <class T> void f() { S<T> x; x.y.z; }",
652 {"-fno-delayed-template-parsing"});
653 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
654 EXPECT_FALSE(isMutated(Results, AST.get()));
655}
656
657TEST(ExprMutationAnalyzerTest, CastToValue) {
658 const auto AST =
659 tooling::buildASTFromCode("void f() { int x; static_cast<double>(x); }");
660 const auto Results =
661 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
662 EXPECT_FALSE(isMutated(Results, AST.get()));
663}
664
665TEST(ExprMutationAnalyzerTest, CastToRefModified) {
666 auto AST = tooling::buildASTFromCode(
667 "void f() { int x; static_cast<int &>(x) = 10; }");
668 auto Results =
669 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
670 EXPECT_THAT(mutatedBy(Results, AST.get()),
671 ElementsAre("static_cast<int &>(x) = 10"));
672
673 AST = tooling::buildASTFromCode(
674 "typedef int& IntRef;"
675 "void f() { int x; static_cast<IntRef>(x) = 10; }");
676 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
677 EXPECT_THAT(mutatedBy(Results, AST.get()),
678 ElementsAre("static_cast<IntRef>(x) = 10"));
679}
680
681TEST(ExprMutationAnalyzerTest, CastToRefNotModified) {
682 const auto AST =
683 tooling::buildASTFromCode("void f() { int x; static_cast<int&>(x); }");
684 const auto Results =
685 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
686 EXPECT_FALSE(isMutated(Results, AST.get()));
687}
688
689TEST(ExprMutationAnalyzerTest, CastToConstRef) {
690 auto AST = tooling::buildASTFromCode(
691 "void f() { int x; static_cast<const int&>(x); }");
692 auto Results =
693 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
694 EXPECT_FALSE(isMutated(Results, AST.get()));
695
696 AST =
697 tooling::buildASTFromCode("typedef const int& CIntRef;"
698 "void f() { int x; static_cast<CIntRef>(x); }");
699 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
700 EXPECT_FALSE(isMutated(Results, AST.get()));
701}
702
703TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) {
704 const auto AST =
705 tooling::buildASTFromCode("void f() { int x; [=]() { x = 10; }; }");
706 const auto Results =
707 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
708 EXPECT_FALSE(isMutated(Results, AST.get()));
709}
710
711TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) {
712 const auto AST =
713 tooling::buildASTFromCode("void f() { int x; [x]() { x = 10; }; }");
714 const auto Results =
715 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
716 EXPECT_FALSE(isMutated(Results, AST.get()));
717}
718
719TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) {
720 const auto AST =
721 tooling::buildASTFromCode("void f() { int x; [&]() { x = 10; }; }");
722 const auto Results =
723 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
724 EXPECT_THAT(mutatedBy(Results, AST.get()),
725 ElementsAre(ResultOf(removeSpace, "[&](){x=10;}")));
726}
727
728TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) {
729 const auto AST =
730 tooling::buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }");
731 const auto Results =
732 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
733 EXPECT_THAT(mutatedBy(Results, AST.get()),
734 ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}")));
735}
736
737TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) {
738 auto AST = tooling::buildASTFromCode(
739 "void f() { int x[2]; for (int& e : x) e = 10; }");
740 auto Results =
741 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
742 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
743
744 AST = tooling::buildASTFromCode(
745 "typedef int& IntRef;"
746 "void f() { int x[2]; for (IntRef e : x) e = 10; }");
747 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
748 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
749}
750
751TEST(ExprMutationAnalyzerTest, RangeForArrayByRefNotModified) {
752 const auto AST =
753 tooling::buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }");
754 const auto Results =
755 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
756 EXPECT_FALSE(isMutated(Results, AST.get()));
757}
758
759TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) {
760 auto AST = tooling::buildASTFromCode(
761 "void f() { int x[2]; for (int e : x) e = 10; }");
762 auto Results =
763 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
764 EXPECT_FALSE(isMutated(Results, AST.get()));
765
766 AST = tooling::buildASTFromCode(
767 "void f() { int* x[2]; for (int* e : x) e = nullptr; }");
768 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
769 EXPECT_FALSE(isMutated(Results, AST.get()));
770
771 AST = tooling::buildASTFromCode(
772 "typedef int* IntPtr;"
773 "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }");
774 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
775 EXPECT_FALSE(isMutated(Results, AST.get()));
776}
777
778TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) {
779 auto AST = tooling::buildASTFromCode(
780 "void f() { int x[2]; for (const int& e : x) e; }");
781 auto Results =
782 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
783 EXPECT_FALSE(isMutated(Results, AST.get()));
784
785 AST = tooling::buildASTFromCode(
786 "typedef const int& CIntRef;"
787 "void f() { int x[2]; for (CIntRef e : x) e; }");
788 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
789 EXPECT_FALSE(isMutated(Results, AST.get()));
790}
791
792TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) {
793 const auto AST =
794 tooling::buildASTFromCode("struct V { int* begin(); int* end(); };"
795 "void f() { V x; for (int& e : x) e = 10; }");
796 const auto Results =
797 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
798 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
799}
800
801TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) {
802 const auto AST =
803 tooling::buildASTFromCode("struct V { int* begin(); int* end(); };"
804 "void f() { V x; for (int& e : x) e; }");
805 const auto Results =
806 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
807 EXPECT_FALSE(isMutated(Results, AST.get()));
808}
809
810TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) {
811 const auto AST = tooling::buildASTFromCode(
812 "struct V { const int* begin() const; const int* end() const; };"
813 "void f() { V x; for (int e : x) e; }");
814 const auto Results =
815 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
816 EXPECT_FALSE(isMutated(Results, AST.get()));
817}
818
819TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) {
820 const auto AST = tooling::buildASTFromCode(
821 "struct V { const int* begin() const; const int* end() const; };"
822 "void f() { V x; for (const int& e : x) e; }");
823 const auto Results =
824 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
825 EXPECT_FALSE(isMutated(Results, AST.get()));
826}
827
828TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) {
829 auto AST = tooling::buildASTFromCode(
830 "void f() { int x, y; decltype(x = 10) z = y; }");
831 auto Results =
832 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
833 EXPECT_FALSE(isMutated(Results, AST.get()));
834
835 AST = tooling::buildASTFromCode(
836 "void f() { int x, y; __typeof(x = 10) z = y; }");
837 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
838 EXPECT_FALSE(isMutated(Results, AST.get()));
839
840 AST = tooling::buildASTFromCode(
841 "void f() { int x, y; __typeof__(x = 10) z = y; }");
842 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
843 EXPECT_FALSE(isMutated(Results, AST.get()));
844
845 AST = tooling::buildASTFromCode("void f() { int x; sizeof(x = 10); }");
846 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
847 EXPECT_FALSE(isMutated(Results, AST.get()));
848
849 AST = tooling::buildASTFromCode("void f() { int x; alignof(x = 10); }");
850 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
851 EXPECT_FALSE(isMutated(Results, AST.get()));
852
853 AST = tooling::buildASTFromCode("void f() { int x; noexcept(x = 10); }");
854 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
855 EXPECT_FALSE(isMutated(Results, AST.get()));
856
857 AST = tooling::buildASTFromCodeWithArgs("namespace std { class type_info; }"
858 "void f() { int x; typeid(x = 10); }",
859 {"-frtti"});
860 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
861 EXPECT_FALSE(isMutated(Results, AST.get()));
862
863 AST = tooling::buildASTFromCode(
864 "void f() { int x; _Generic(x = 10, int: 0, default: 1); }");
865 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
866 EXPECT_FALSE(isMutated(Results, AST.get()));
867}
868
869TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) {
870 auto AST = tooling::buildASTFromCode("void f() { int x; sizeof(int[x++]); }");
871 auto Results =
872 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
873 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++"));
874
875 AST = tooling::buildASTFromCodeWithArgs(
876 "namespace std { class type_info; }"
877 "struct A { virtual ~A(); }; struct B : A {};"
878 "struct X { A& f(); }; void f() { X x; typeid(x.f()); }",
879 {"-frtti"});
880 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
881 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()"));
882}
883
884TEST(ExprMutationAnalyzerTest, UniquePtr) {
885 const std::string UniquePtrDef =
886 "template <class T> struct UniquePtr {"
887 " UniquePtr();"
888 " UniquePtr(const UniquePtr&) = delete;"
889 " UniquePtr(UniquePtr&&);"
890 " UniquePtr& operator=(const UniquePtr&) = delete;"
891 " UniquePtr& operator=(UniquePtr&&);"
892 " T& operator*() const;"
893 " T* operator->() const;"
894 "};";
895
896 auto AST = tooling::buildASTFromCode(
897 UniquePtrDef + "void f() { UniquePtr<int> x; *x = 10; }");
898 auto Results =
899 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
900 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10"));
901
902 AST = tooling::buildASTFromCode(UniquePtrDef +
903 "void f() { UniquePtr<int> x; *x; }");
904 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
905 EXPECT_FALSE(isMutated(Results, AST.get()));
906
907 AST = tooling::buildASTFromCode(UniquePtrDef +
908 "void f() { UniquePtr<const int> x; *x; }");
909 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
910 EXPECT_FALSE(isMutated(Results, AST.get()));
911
912 AST = tooling::buildASTFromCode(UniquePtrDef +
913 "struct S { int v; };"
914 "void f() { UniquePtr<S> x; x->v; }");
915 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
916 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
917
918 AST = tooling::buildASTFromCode(UniquePtrDef +
919 "struct S { int v; };"
920 "void f() { UniquePtr<const S> x; x->v; }");
921 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
922 EXPECT_FALSE(isMutated(Results, AST.get()));
923
924 AST = tooling::buildASTFromCode(UniquePtrDef +
925 "struct S { void mf(); };"
926 "void f() { UniquePtr<S> x; x->mf(); }");
927 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
928 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
929
930 AST = tooling::buildASTFromCode(
931 UniquePtrDef + "struct S { void mf() const; };"
932 "void f() { UniquePtr<const S> x; x->mf(); }");
933 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
934 EXPECT_FALSE(isMutated(Results, AST.get()));
935
936 AST = tooling::buildASTFromCodeWithArgs(
937 UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }",
938 {"-fno-delayed-template-parsing"});
939 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
940 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()"));
941}
942
943} // namespace clang