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