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, CommaExprWithAnAssigment) {
885   const auto AST =
886       buildASTFromCodeWithArgs("void f() { int x; int y; (x, y) = 5; }",
887                                {"-Wno-unused-value"});
888   const auto Results =
889       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
890   EXPECT_TRUE(isMutated(Results, AST.get()));
891 }
892 
893 TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) {
894   const auto AST =
895       buildASTFromCodeWithArgs("void f() { int x; int y; (x, y)++; }",
896                                {"-Wno-unused-value"});
897   const auto Results =
898       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
899   EXPECT_TRUE(isMutated(Results, AST.get()));
900 }
901 
902 TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) {
903   const auto AST =
904       buildASTFromCodeWithArgs("class A { public: int mem; void f() { mem ++; } };"
905                                "void fn() { A o1, o2; (o1, o2).f(); }",
906                                {"-Wno-unused-value"});
907   const auto Results =
908       match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
909   EXPECT_TRUE(isMutated(Results, AST.get()));
910 }
911 
912 TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) {
913   const auto AST =
914       buildASTFromCodeWithArgs("class A { public: int mem; void f() const  { } };"
915                                "void fn() { A o1, o2; (o1, o2).f(); }",
916                                {"-Wno-unused-value"});
917   const auto Results =
918       match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
919   EXPECT_FALSE(isMutated(Results, AST.get()));
920 }
921 
922 TEST(ExprMutationAnalyzerTest, CommaExprWithCallExpr) {
923   const auto AST =
924       buildASTFromCodeWithArgs("class A { public: int mem; void f(A &O1) {} };"
925                                "void fn() { A o1, o2; o2.f((o2, o1)); }",
926                                {"-Wno-unused-value"});
927   const auto Results =
928       match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
929   EXPECT_TRUE(isMutated(Results, AST.get()));
930 }
931 
932 TEST(ExprMutationAnalyzerTest, CommaExprWithCallUnresolved) {
933   auto AST = buildASTFromCodeWithArgs(
934       "template <class T> struct S;"
935       "template <class T> void f() { S<T> s; int x, y; s.mf((y, x)); }",
936       {"-fno-delayed-template-parsing", "-Wno-unused-value"});
937   auto Results =
938       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
939   EXPECT_TRUE(isMutated(Results, AST.get()));
940 
941   AST = buildASTFromCodeWithArgs(
942       "template <class T> void f(T t) { int x, y; g(t, (y, x)); }",
943       {"-fno-delayed-template-parsing", "-Wno-unused-value"});
944   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
945   EXPECT_TRUE(isMutated(Results, AST.get()));
946 }
947 
948 TEST(ExprMutationAnalyzerTest, CommaExprParmRef) {
949   const auto AST =
950       buildASTFromCodeWithArgs("class A { public: int mem;};"
951                                "extern void fn(A &o1);"
952                                "void fn2 () { A o1, o2; fn((o2, o1)); } ",
953                                {"-Wno-unused-value"});
954   const auto Results =
955       match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
956   EXPECT_TRUE(isMutated(Results, AST.get()));
957 }
958 
959 TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) {
960   const auto AST =
961       buildASTFromCodeWithArgs("class A { public: int mem;};"
962                                "void fn () { A o1, o2;"
963                                "void *addr = &(o2, o1); } ",
964                                {"-Wno-unused-value"});
965   const auto Results =
966       match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
967   EXPECT_TRUE(isMutated(Results, AST.get()));
968 }
969 
970 TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsValue) {
971   auto AST = buildASTFromCodeWithArgs("int f() { int x, y; return (x, y); }",
972                                       {"-Wno-unused-value"});
973   auto Results =
974       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
975   EXPECT_FALSE(isMutated(Results, AST.get()));
976 }
977 
978 TEST(ExprMutationAnalyzerTest, CommaEpxrAsReturnAsNonConstRef) {
979   const auto AST =
980       buildASTFromCodeWithArgs("int& f() { int x, y; return (y, x); }",
981                                {"-Wno-unused-value"});
982   const auto Results =
983       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
984   EXPECT_TRUE(isMutated(Results, AST.get()));
985 }
986 
987 TEST(ExprMutationAnalyzerTest, CommaExprAsArrayToPointerDecay) {
988   const auto AST =
989       buildASTFromCodeWithArgs("void g(int*); "
990                                "void f() { int x[2], y[2]; g((y, x)); }",
991                                {"-Wno-unused-value"});
992   const auto Results =
993       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
994   EXPECT_TRUE(isMutated(Results, AST.get()));
995 }
996 
997 TEST(ExprMutationAnalyzerTest, CommaExprAsUniquePtr) {
998   const std::string UniquePtrDef =
999       "template <class T> struct UniquePtr {"
1000       "  UniquePtr();"
1001       "  UniquePtr(const UniquePtr&) = delete;"
1002       "  T& operator*() const;"
1003       "  T* operator->() const;"
1004       "};";
1005   const auto AST = buildASTFromCodeWithArgs(
1006       UniquePtrDef + "template <class T> void f() "
1007                      "{ UniquePtr<T> x; UniquePtr<T> y;"
1008                      " (y, x)->mf(); }",
1009       {"-fno-delayed-template-parsing", "-Wno-unused-value"});
1010   const auto Results =
1011       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1012   EXPECT_TRUE(isMutated(Results, AST.get()));
1013 }
1014 
1015 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) {
1016   const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }");
1017   const auto Results =
1018       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1019   EXPECT_FALSE(isMutated(Results, AST.get()));
1020 }
1021 
1022 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) {
1023   const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }");
1024   const auto Results =
1025       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1026   EXPECT_FALSE(isMutated(Results, AST.get()));
1027 }
1028 
1029 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) {
1030   const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }");
1031   const auto Results =
1032       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1033   EXPECT_THAT(mutatedBy(Results, AST.get()),
1034               ElementsAre(ResultOf(removeSpace, "[&](){x=10;}")));
1035 }
1036 
1037 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) {
1038   const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }");
1039   const auto Results =
1040       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1041   EXPECT_THAT(mutatedBy(Results, AST.get()),
1042               ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}")));
1043 }
1044 
1045 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) {
1046   auto AST =
1047       buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }");
1048   auto Results =
1049       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1050   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
1051 
1052   AST = buildASTFromCode("typedef int& IntRef;"
1053                          "void f() { int x[2]; for (IntRef e : x) e = 10; }");
1054   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1055   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
1056 }
1057 
1058 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefNotModified) {
1059   const auto AST =
1060       buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }");
1061   const auto Results =
1062       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1063   EXPECT_FALSE(isMutated(Results, AST.get()));
1064 }
1065 
1066 TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) {
1067   auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }");
1068   auto Results =
1069       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1070   EXPECT_FALSE(isMutated(Results, AST.get()));
1071 
1072   AST =
1073       buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }");
1074   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1075   EXPECT_FALSE(isMutated(Results, AST.get()));
1076 
1077   AST = buildASTFromCode(
1078       "typedef int* IntPtr;"
1079       "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }");
1080   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1081   EXPECT_FALSE(isMutated(Results, AST.get()));
1082 }
1083 
1084 TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) {
1085   auto AST =
1086       buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }");
1087   auto Results =
1088       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1089   EXPECT_FALSE(isMutated(Results, AST.get()));
1090 
1091   AST = buildASTFromCode("typedef const int& CIntRef;"
1092                          "void f() { int x[2]; for (CIntRef e : x) e; }");
1093   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1094   EXPECT_FALSE(isMutated(Results, AST.get()));
1095 }
1096 
1097 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) {
1098   const auto AST =
1099       buildASTFromCode("struct V { int* begin(); int* end(); };"
1100                        "void f() { V x; for (int& e : x) e = 10; }");
1101   const auto Results =
1102       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1103   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
1104 }
1105 
1106 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) {
1107   const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };"
1108                                     "void f() { V x; for (int& e : x) e; }");
1109   const auto Results =
1110       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1111   EXPECT_FALSE(isMutated(Results, AST.get()));
1112 }
1113 
1114 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) {
1115   const auto AST = buildASTFromCode(
1116       "struct V { const int* begin() const; const int* end() const; };"
1117       "void f() { V x; for (int e : x) e; }");
1118   const auto Results =
1119       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1120   EXPECT_FALSE(isMutated(Results, AST.get()));
1121 }
1122 
1123 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) {
1124   const auto AST = buildASTFromCode(
1125       "struct V { const int* begin() const; const int* end() const; };"
1126       "void f() { V x; for (const int& e : x) e; }");
1127   const auto Results =
1128       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1129   EXPECT_FALSE(isMutated(Results, AST.get()));
1130 }
1131 
1132 TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) {
1133   auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }");
1134   auto Results =
1135       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1136   EXPECT_FALSE(isMutated(Results, AST.get()));
1137 
1138   AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }");
1139   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1140   EXPECT_FALSE(isMutated(Results, AST.get()));
1141 
1142   AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }");
1143   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1144   EXPECT_FALSE(isMutated(Results, AST.get()));
1145 
1146   AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }");
1147   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1148   EXPECT_FALSE(isMutated(Results, AST.get()));
1149 
1150   AST = buildASTFromCode("void f() { int x; alignof(x = 10); }");
1151   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1152   EXPECT_FALSE(isMutated(Results, AST.get()));
1153 
1154   AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }");
1155   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1156   EXPECT_FALSE(isMutated(Results, AST.get()));
1157 
1158   AST = buildASTFromCodeWithArgs("namespace std { class type_info; }"
1159                                  "void f() { int x; typeid(x = 10); }",
1160                                  {"-frtti"});
1161   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1162   EXPECT_FALSE(isMutated(Results, AST.get()));
1163 
1164   AST = buildASTFromCode(
1165       "void f() { int x; _Generic(x = 10, int: 0, default: 1); }");
1166   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1167   EXPECT_FALSE(isMutated(Results, AST.get()));
1168 }
1169 
1170 TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) {
1171   auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }");
1172   auto Results =
1173       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1174   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++"));
1175 
1176   AST = buildASTFromCodeWithArgs(
1177       "namespace std { class type_info; }"
1178       "struct A { virtual ~A(); }; struct B : A {};"
1179       "struct X { A& f(); }; void f() { X x; typeid(x.f()); }",
1180       {"-frtti"});
1181   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1182   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()"));
1183 }
1184 
1185 TEST(ExprMutationAnalyzerTest, UniquePtr) {
1186   const std::string UniquePtrDef =
1187       "template <class T> struct UniquePtr {"
1188       "  UniquePtr();"
1189       "  UniquePtr(const UniquePtr&) = delete;"
1190       "  UniquePtr(UniquePtr&&);"
1191       "  UniquePtr& operator=(const UniquePtr&) = delete;"
1192       "  UniquePtr& operator=(UniquePtr&&);"
1193       "  T& operator*() const;"
1194       "  T* operator->() const;"
1195       "};";
1196 
1197   auto AST = buildASTFromCode(UniquePtrDef +
1198                               "void f() { UniquePtr<int> x; *x = 10; }");
1199   auto Results =
1200       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1201   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10"));
1202 
1203   AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr<int> x; *x; }");
1204   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1205   EXPECT_FALSE(isMutated(Results, AST.get()));
1206 
1207   AST = buildASTFromCode(UniquePtrDef +
1208                          "void f() { UniquePtr<const int> x; *x; }");
1209   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1210   EXPECT_FALSE(isMutated(Results, AST.get()));
1211 
1212   AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };"
1213                                         "void f() { UniquePtr<S> x; x->v; }");
1214   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1215   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
1216 
1217   AST = buildASTFromCode(UniquePtrDef +
1218                          "struct S { int v; };"
1219                          "void f() { UniquePtr<const S> x; x->v; }");
1220   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1221   EXPECT_FALSE(isMutated(Results, AST.get()));
1222 
1223   AST =
1224       buildASTFromCode(UniquePtrDef + "struct S { void mf(); };"
1225                                       "void f() { UniquePtr<S> x; x->mf(); }");
1226   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1227   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
1228 
1229   AST = buildASTFromCode(UniquePtrDef +
1230                          "struct S { void mf() const; };"
1231                          "void f() { UniquePtr<const S> x; x->mf(); }");
1232   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1233   EXPECT_FALSE(isMutated(Results, AST.get()));
1234 
1235   AST = buildASTFromCodeWithArgs(
1236       UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }",
1237       {"-fno-delayed-template-parsing"});
1238   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1239   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()"));
1240 }
1241 
1242 TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) {
1243   const std::string Reproducer =
1244       "namespace std {"
1245       "template <class T> T forward(T & A) { return static_cast<T&&>(A); }"
1246       "template <class T> struct __bind {"
1247       "  T f;"
1248       "  template <class V> __bind(T v, V &&) : f(forward(v)) {}"
1249       "};"
1250       "}"
1251       "void f() {"
1252       "  int x = 42;"
1253       "  auto Lambda = [] {};"
1254       "  std::__bind<decltype(Lambda)>(Lambda, x);"
1255       "}";
1256   auto AST11 = buildASTFromCodeWithArgs(Reproducer, {"-std=c++11"});
1257   auto Results11 =
1258       match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext());
1259   EXPECT_FALSE(isMutated(Results11, AST11.get()));
1260 }
1261 } // namespace clang
1262