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