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