Clang Project

clang_source_code/unittests/Analysis/ExprMutationAnalyzerTest.cpp
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
18namespace clang {
19
20using namespace clang::ast_matchers;
21using ::testing::ElementsAre;
22using ::testing::IsEmpty;
23using ::testing::ResultOf;
24using ::testing::StartsWith;
25using ::testing::Values;
26
27namespace {
28
29using ExprMatcher = internal::Matcher<Expr>;
30using StmtMatcher = internal::Matcher<Stmt>;
31
32std::unique_ptr<ASTUnit>
33buildASTFromCodeWithArgs(const Twine &Code,
34                         const std::vector<std::string> &Args) {
35  SmallString<1024CodeStorage;
36  auto AST =
37      tooling::buildASTFromCodeWithArgs(Code.toStringRef(CodeStorage), Args);
38  EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
39  return AST;
40}
41
42std::unique_ptr<ASTUnitbuildASTFromCode(const Twine &Code) {
43  return buildASTFromCodeWithArgs(Code, {});
44}
45
46ExprMatcher declRefTo(StringRef Name) {
47  return declRefExpr(to(namedDecl(hasName(Name))));
48}
49
50StmtMatcher withEnclosingCompound(ExprMatcher Matcher) {
51  return expr(Matcher, hasAncestor(compoundStmt().bind("stmt"))).bind("expr");
52}
53
54bool isMutated(const SmallVectorImpl<BoundNodes> &ResultsASTUnit *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
60SmallVector<std::string1>
61mutatedBy(const SmallVectorImpl<BoundNodes> &ResultsASTUnit *AST) {
62  const auto *const S = selectFirst<Stmt>("stmt"Results);
63  SmallVector<std::string1Chain;
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
76std::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
83const 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
89const 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
95const 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
104TEST(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
111class AssignmentTest : public ::testing::TestWithParam<std::string> {};
112
113TEST_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
121INSTANTIATE_TEST_CASE_P(AllAssignmentOperators, AssignmentTest,
122                        Values("=""+=""-=""*=""/=""%=""&=""|=",
123                               "^=""<<="">>="), );
124
125class IncDecTest : public ::testing::TestWithParam<std::string> {};
126
127TEST_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
135INSTANTIATE_TEST_CASE_P(AllIncDecOperators, IncDecTest,
136                        Values("++x""--x""x++""x--"), );
137
138TEST(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
146TEST(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
168TEST(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
176TEST(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
184TEST(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
192TEST(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
228TEST(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
260TEST(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
313TEST(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
353TEST(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
380TEST(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
403TEST(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
465TEST(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
481TEST(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
534TEST(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
550TEST(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
557TEST(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
564TEST(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
573TEST(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
581TEST(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
588TEST(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
596TEST(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
612TEST(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
630TEST(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
650TEST(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
658TEST(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
666TEST(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
726TEST(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
783TEST(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
790TEST(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
797TEST(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
819TEST(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
840TEST(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
848TEST(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
863TEST(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
871TEST(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
884TEST(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
893TEST(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
902TEST(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
912TEST(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
922TEST(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
932TEST(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
948TEST(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
959TEST(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
970TEST(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
978TEST(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
987TEST(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
997TEST(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
1015TEST(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
1022TEST(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
1029TEST(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
1037TEST(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
1045TEST(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
1058TEST(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
1066TEST(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
1084TEST(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
1097TEST(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
1106TEST(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
1114TEST(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
1123TEST(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
1132TEST(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
1170TEST(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
1185TEST(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
1242TEST(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