xref: /llvm-project/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp (revision 53ea5ffcb38d428e446d357f310e9c28957eaec7)
1e9192f83SShuai Wang //===---------- ExprMutationAnalyzerTest.cpp ------------------------------===//
2e9192f83SShuai Wang //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e9192f83SShuai Wang //
7e9192f83SShuai Wang //===----------------------------------------------------------------------===//
8e9192f83SShuai Wang 
9e9192f83SShuai Wang #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
10e517e5cfSJonas Toth #include "clang/AST/TypeLoc.h"
11e9192f83SShuai Wang #include "clang/ASTMatchers/ASTMatchFinder.h"
12e9192f83SShuai Wang #include "clang/ASTMatchers/ASTMatchers.h"
136e31714dSCongcong Cai #include "clang/Frontend/ASTUnit.h"
14e9192f83SShuai Wang #include "clang/Tooling/Tooling.h"
15e9192f83SShuai Wang #include "gmock/gmock.h"
16e9192f83SShuai Wang #include "gtest/gtest.h"
17*53ea5ffcSCongcong Cai #include <cassert>
18e9192f83SShuai Wang #include <cctype>
19e9192f83SShuai Wang 
20e9192f83SShuai Wang namespace clang {
21e9192f83SShuai Wang 
22e9192f83SShuai Wang using namespace clang::ast_matchers;
23e9192f83SShuai Wang using ::testing::ElementsAre;
24e9192f83SShuai Wang using ::testing::ResultOf;
25e9192f83SShuai Wang using ::testing::Values;
26e9192f83SShuai Wang 
27e9192f83SShuai Wang namespace {
28e9192f83SShuai Wang 
29e9192f83SShuai Wang using ExprMatcher = internal::Matcher<Expr>;
30e9192f83SShuai Wang using StmtMatcher = internal::Matcher<Stmt>;
31e9192f83SShuai Wang 
32b81bcb3aSShuai Wang std::unique_ptr<ASTUnit>
33b81bcb3aSShuai Wang buildASTFromCodeWithArgs(const Twine &Code,
34b81bcb3aSShuai Wang                          const std::vector<std::string> &Args) {
35973fcc25SAlexander Kornienko   SmallString<1024> CodeStorage;
36973fcc25SAlexander Kornienko   auto AST =
37973fcc25SAlexander Kornienko       tooling::buildASTFromCodeWithArgs(Code.toStringRef(CodeStorage), Args);
38b81bcb3aSShuai Wang   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
39b81bcb3aSShuai Wang   return AST;
40b81bcb3aSShuai Wang }
41b81bcb3aSShuai Wang 
42b81bcb3aSShuai Wang std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code) {
43b81bcb3aSShuai Wang   return buildASTFromCodeWithArgs(Code, {});
44b81bcb3aSShuai Wang }
45b81bcb3aSShuai Wang 
46e9192f83SShuai Wang ExprMatcher declRefTo(StringRef Name) {
476e31714dSCongcong Cai   return declRefExpr(to(namedDecl(hasName(Name)).bind("decl")));
48e9192f83SShuai Wang }
49e9192f83SShuai Wang 
50e9192f83SShuai Wang StmtMatcher withEnclosingCompound(ExprMatcher Matcher) {
51e9192f83SShuai Wang   return expr(Matcher, hasAncestor(compoundStmt().bind("stmt"))).bind("expr");
52e9192f83SShuai Wang }
53e9192f83SShuai Wang 
54e9192f83SShuai Wang bool isMutated(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
55e9192f83SShuai Wang   const auto *const S = selectFirst<Stmt>("stmt", Results);
56e9192f83SShuai Wang   const auto *const E = selectFirst<Expr>("expr", Results);
57027899daSAlexander Kornienko   TraversalKindScope RAII(AST->getASTContext(), TK_AsIs);
58e9192f83SShuai Wang   return ExprMutationAnalyzer(*S, AST->getASTContext()).isMutated(E);
59e9192f83SShuai Wang }
60e9192f83SShuai Wang 
616e31714dSCongcong Cai bool isDeclMutated(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
626e31714dSCongcong Cai   const auto *const S = selectFirst<Stmt>("stmt", Results);
636e31714dSCongcong Cai   const auto *const D = selectFirst<Decl>("decl", Results);
646e31714dSCongcong Cai   TraversalKindScope RAII(AST->getASTContext(), TK_AsIs);
656e31714dSCongcong Cai   return ExprMutationAnalyzer(*S, AST->getASTContext()).isMutated(D);
666e31714dSCongcong Cai }
676e31714dSCongcong Cai 
68e9192f83SShuai Wang SmallVector<std::string, 1>
69e9192f83SShuai Wang mutatedBy(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
70e9192f83SShuai Wang   const auto *const S = selectFirst<Stmt>("stmt", Results);
71e9192f83SShuai Wang   SmallVector<std::string, 1> Chain;
72e9192f83SShuai Wang   ExprMutationAnalyzer Analyzer(*S, AST->getASTContext());
73e517e5cfSJonas Toth 
74e9192f83SShuai Wang   for (const auto *E = selectFirst<Expr>("expr", Results); E != nullptr;) {
75e9192f83SShuai Wang     const Stmt *By = Analyzer.findMutation(E);
76e517e5cfSJonas Toth     if (!By)
77e517e5cfSJonas Toth       break;
78e517e5cfSJonas Toth 
79e517e5cfSJonas Toth     std::string Buffer;
80e517e5cfSJonas Toth     llvm::raw_string_ostream Stream(Buffer);
81e517e5cfSJonas Toth     By->printPretty(Stream, nullptr, AST->getASTContext().getPrintingPolicy());
82918972bdSJOE1994     Chain.emplace_back(StringRef(Buffer).trim().str());
83e9192f83SShuai Wang     E = dyn_cast<DeclRefExpr>(By);
84e9192f83SShuai Wang   }
85e9192f83SShuai Wang   return Chain;
86e9192f83SShuai Wang }
87e9192f83SShuai Wang 
88e9192f83SShuai Wang std::string removeSpace(std::string s) {
89e9192f83SShuai Wang   s.erase(std::remove_if(s.begin(), s.end(),
90d10c995bSSam McCall                          [](char c) { return llvm::isSpace(c); }),
91e9192f83SShuai Wang           s.end());
92e9192f83SShuai Wang   return s;
93e9192f83SShuai Wang }
94e9192f83SShuai Wang 
954305993cSShuai Wang const std::string StdRemoveReference =
964305993cSShuai Wang     "namespace std {"
974305993cSShuai Wang     "template<class T> struct remove_reference { typedef T type; };"
984305993cSShuai Wang     "template<class T> struct remove_reference<T&> { typedef T type; };"
994305993cSShuai Wang     "template<class T> struct remove_reference<T&&> { typedef T type; }; }";
1004305993cSShuai Wang 
1014305993cSShuai Wang const std::string StdMove =
1024305993cSShuai Wang     "namespace std {"
1034305993cSShuai Wang     "template<class T> typename remove_reference<T>::type&& "
1044305993cSShuai Wang     "move(T&& t) noexcept {"
1054305993cSShuai Wang     "return static_cast<typename remove_reference<T>::type&&>(t); } }";
1064305993cSShuai Wang 
1074305993cSShuai Wang const std::string StdForward =
1084305993cSShuai Wang     "namespace std {"
1094305993cSShuai Wang     "template<class T> T&& "
1104305993cSShuai Wang     "forward(typename remove_reference<T>::type& t) noexcept { return t; }"
1114305993cSShuai Wang     "template<class T> T&& "
112b81bcb3aSShuai Wang     "forward(typename remove_reference<T>::type&& t) noexcept { return t; } }";
1134305993cSShuai Wang 
114e9192f83SShuai Wang } // namespace
115e9192f83SShuai Wang 
116e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, Trivial) {
117b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x; x; }");
118e9192f83SShuai Wang   const auto Results =
119e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
120e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
121e9192f83SShuai Wang }
122e9192f83SShuai Wang 
123e9192f83SShuai Wang class AssignmentTest : public ::testing::TestWithParam<std::string> {};
124e9192f83SShuai Wang 
125e517e5cfSJonas Toth // This test is for the most basic and direct modification of a variable,
126e517e5cfSJonas Toth // assignment to it (e.g. `x = 10;`).
127e517e5cfSJonas Toth // It additionally tests that references to a variable are not only captured
128e517e5cfSJonas Toth // directly but expressions that result in the variable are handled, too.
129e517e5cfSJonas Toth // This includes the comma operator, parens and the ternary operator.
130e9192f83SShuai Wang TEST_P(AssignmentTest, AssignmentModifies) {
131e517e5cfSJonas Toth   // Test the detection of the raw expression modifications.
132ce5fecb7STridacnid   {
133e9192f83SShuai Wang     const std::string ModExpr = "x " + GetParam() + " 10";
134b81bcb3aSShuai Wang     const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }");
135e9192f83SShuai Wang     const auto Results =
136e9192f83SShuai Wang         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
137e9192f83SShuai Wang     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
138e9192f83SShuai Wang   }
139e9192f83SShuai Wang 
140e517e5cfSJonas Toth   // Test the detection if the expression is surrounded by parens.
141ce5fecb7STridacnid   {
142ce5fecb7STridacnid     const std::string ModExpr = "(x) " + GetParam() + " 10";
143ce5fecb7STridacnid     const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }");
144ce5fecb7STridacnid     const auto Results =
145ce5fecb7STridacnid         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
146ce5fecb7STridacnid     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
147ce5fecb7STridacnid   }
148e517e5cfSJonas Toth 
149e517e5cfSJonas Toth   // Test the detection if the comma operator yields the expression as result.
150e517e5cfSJonas Toth   {
151e517e5cfSJonas Toth     const std::string ModExpr = "x " + GetParam() + " 10";
152e517e5cfSJonas Toth     const auto AST = buildASTFromCodeWithArgs(
153e517e5cfSJonas Toth         "void f() { int x, y; y, " + ModExpr + "; }", {"-Wno-unused-value"});
154e517e5cfSJonas Toth     const auto Results =
155e517e5cfSJonas Toth         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
156e517e5cfSJonas Toth     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
157e517e5cfSJonas Toth   }
158e517e5cfSJonas Toth 
159e517e5cfSJonas Toth   // Ensure no detection if the comma operator does not yield the expression as
160e517e5cfSJonas Toth   // result.
161e517e5cfSJonas Toth   {
162e517e5cfSJonas Toth     const std::string ModExpr = "y, x, y " + GetParam() + " 10";
163e517e5cfSJonas Toth     const auto AST = buildASTFromCodeWithArgs(
164e517e5cfSJonas Toth         "void f() { int x, y; " + ModExpr + "; }", {"-Wno-unused-value"});
165e517e5cfSJonas Toth     const auto Results =
166e517e5cfSJonas Toth         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
167e517e5cfSJonas Toth     EXPECT_FALSE(isMutated(Results, AST.get()));
168e517e5cfSJonas Toth   }
169e517e5cfSJonas Toth 
170e517e5cfSJonas Toth   // Test the detection if the a ternary operator can result in the expression.
171e517e5cfSJonas Toth   {
172e517e5cfSJonas Toth     const std::string ModExpr = "(y != 0 ? y : x) " + GetParam() + " 10";
173e517e5cfSJonas Toth     const auto AST =
174e517e5cfSJonas Toth         buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }");
175e517e5cfSJonas Toth     const auto Results =
176e517e5cfSJonas Toth         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
177e517e5cfSJonas Toth     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
178e517e5cfSJonas Toth   }
179e517e5cfSJonas Toth 
180e517e5cfSJonas Toth   // Test the detection if the a ternary operator can result in the expression
181e517e5cfSJonas Toth   // through multiple nesting of ternary operators.
182e517e5cfSJonas Toth   {
183e517e5cfSJonas Toth     const std::string ModExpr =
184e517e5cfSJonas Toth         "(y != 0 ? (y > 5 ? y : x) : (y)) " + GetParam() + " 10";
185e517e5cfSJonas Toth     const auto AST =
186e517e5cfSJonas Toth         buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }");
187e517e5cfSJonas Toth     const auto Results =
188e517e5cfSJonas Toth         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
189e517e5cfSJonas Toth     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
190e517e5cfSJonas Toth   }
191e517e5cfSJonas Toth 
192e517e5cfSJonas Toth   // Test the detection if the a ternary operator can result in the expression
193e517e5cfSJonas Toth   // with additional parens.
194e517e5cfSJonas Toth   {
195e517e5cfSJonas Toth     const std::string ModExpr = "(y != 0 ? (y) : ((x))) " + GetParam() + " 10";
196e517e5cfSJonas Toth     const auto AST =
197e517e5cfSJonas Toth         buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }");
198e517e5cfSJonas Toth     const auto Results =
199e517e5cfSJonas Toth         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
200e517e5cfSJonas Toth     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
201e517e5cfSJonas Toth   }
202e517e5cfSJonas Toth 
203e517e5cfSJonas Toth   // Test the detection for the binary conditional operator.
204e517e5cfSJonas Toth   {
205e517e5cfSJonas Toth     const std::string ModExpr = "(y ?: x) " + GetParam() + " 10";
206e517e5cfSJonas Toth     const auto AST =
207e517e5cfSJonas Toth         buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }");
208e517e5cfSJonas Toth     const auto Results =
209e517e5cfSJonas Toth         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
210e517e5cfSJonas Toth     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
211e517e5cfSJonas Toth   }
212ce5fecb7STridacnid }
213ce5fecb7STridacnid 
214d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(AllAssignmentOperators, AssignmentTest,
215e9192f83SShuai Wang                         Values("=", "+=", "-=", "*=", "/=", "%=", "&=", "|=",
216d4d80a29SBenjamin Kramer                                "^=", "<<=", ">>=") );
217e9192f83SShuai Wang 
218e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, AssignmentConditionalWithInheritance) {
219e517e5cfSJonas Toth   const auto AST = buildASTFromCode("struct Base {void nonconst(); };"
220e517e5cfSJonas Toth                                     "struct Derived : Base {};"
221e517e5cfSJonas Toth                                     "static void f() {"
222e517e5cfSJonas Toth                                     "  Derived x, y;"
223e517e5cfSJonas Toth                                     "  Base &b = true ? x : y;"
224e517e5cfSJonas Toth                                     "  b.nonconst();"
225e517e5cfSJonas Toth                                     "}");
226e517e5cfSJonas Toth   const auto Results =
227e517e5cfSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
228e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("b", "b.nonconst()"));
229e517e5cfSJonas Toth }
230e517e5cfSJonas Toth 
231e9192f83SShuai Wang class IncDecTest : public ::testing::TestWithParam<std::string> {};
232e9192f83SShuai Wang 
233e9192f83SShuai Wang TEST_P(IncDecTest, IncDecModifies) {
234e9192f83SShuai Wang   const std::string ModExpr = GetParam();
235b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }");
236e9192f83SShuai Wang   const auto Results =
237e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
238e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
239e9192f83SShuai Wang }
240e9192f83SShuai Wang 
241d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(AllIncDecOperators, IncDecTest,
242ce5fecb7STridacnid                         Values("++x", "--x", "x++", "x--", "++(x)", "--(x)",
243d4d80a29SBenjamin Kramer                                "(x)++", "(x)--") );
244e9192f83SShuai Wang 
245e517e5cfSJonas Toth // Section: member functions
246e517e5cfSJonas Toth 
247e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, NonConstMemberFunc) {
248b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
249e9192f83SShuai Wang       "void f() { struct Foo { void mf(); }; Foo x; x.mf(); }");
250e9192f83SShuai Wang   const auto Results =
251e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
252e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
253e9192f83SShuai Wang }
254e9192f83SShuai Wang 
255e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, AssumedNonConstMemberFunc) {
256b81bcb3aSShuai Wang   auto AST = buildASTFromCodeWithArgs(
257e9192f83SShuai Wang       "struct X { template <class T> void mf(); };"
258e9192f83SShuai Wang       "template <class T> void f() { X x; x.mf<T>(); }",
259e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
260e9192f83SShuai Wang   auto Results =
261e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
262e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf<T>()"));
263e9192f83SShuai Wang 
264b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.mf(); }",
265e9192f83SShuai Wang                                  {"-fno-delayed-template-parsing"});
266e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
267e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
268e9192f83SShuai Wang 
269b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
270e9192f83SShuai Wang       "template <class T> struct X;"
271e9192f83SShuai Wang       "template <class T> void f() { X<T> x; x.mf(); }",
272e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
273e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
274e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
275e9192f83SShuai Wang }
276e9192f83SShuai Wang 
277e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ConstMemberFunc) {
278b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
279e9192f83SShuai Wang       "void f() { struct Foo { void mf() const; }; Foo x; x.mf(); }");
280e9192f83SShuai Wang   const auto Results =
281e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
282e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
283e9192f83SShuai Wang }
284e9192f83SShuai Wang 
285e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, TypeDependentMemberCall) {
286e517e5cfSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
287e517e5cfSJonas Toth       "template <class T> class vector { void push_back(T); }; "
288e517e5cfSJonas Toth       "template <class T> void f() { vector<T> x; x.push_back(T()); }",
289e517e5cfSJonas Toth       {"-fno-delayed-template-parsing"});
290e517e5cfSJonas Toth   const auto Results =
291e517e5cfSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
292e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.push_back(T())"));
293e517e5cfSJonas Toth }
294e517e5cfSJonas Toth 
295feb7b191SCongcong Cai TEST(ExprMutationAnalyzerTest, MemberPointerMemberCall) {
296feb7b191SCongcong Cai   {
297feb7b191SCongcong Cai     const auto AST =
298feb7b191SCongcong Cai         buildASTFromCode("struct X {};"
299feb7b191SCongcong Cai                          "using T = int (X::*)();"
300feb7b191SCongcong Cai                          "void f(X &x, T m) { X &ref = x; (ref.*m)(); }");
301feb7b191SCongcong Cai     const auto Results =
302feb7b191SCongcong Cai         match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext());
303feb7b191SCongcong Cai     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(ref .* m)()"));
304feb7b191SCongcong Cai   }
305feb7b191SCongcong Cai   {
306feb7b191SCongcong Cai     const auto AST =
307feb7b191SCongcong Cai         buildASTFromCode("struct X {};"
308feb7b191SCongcong Cai                          "using T = int (X::*)();"
309feb7b191SCongcong Cai                          "void f(X &x, T const m) { X &ref = x; (ref.*m)(); }");
310feb7b191SCongcong Cai     const auto Results =
311feb7b191SCongcong Cai         match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext());
312feb7b191SCongcong Cai     EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(ref .* m)()"));
313feb7b191SCongcong Cai   }
314feb7b191SCongcong Cai   {
315feb7b191SCongcong Cai     const auto AST =
316feb7b191SCongcong Cai         buildASTFromCode("struct X {};"
317feb7b191SCongcong Cai                          "using T = int (X::*)() const;"
318feb7b191SCongcong Cai                          "void f(X &x, T m) { X &ref = x; (ref.*m)(); }");
319feb7b191SCongcong Cai     const auto Results =
320feb7b191SCongcong Cai         match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext());
321feb7b191SCongcong Cai     EXPECT_FALSE(isMutated(Results, AST.get()));
322feb7b191SCongcong Cai   }
323feb7b191SCongcong Cai }
324feb7b191SCongcong Cai 
325e517e5cfSJonas Toth // Section: overloaded operators
326e517e5cfSJonas Toth 
327e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, NonConstOperator) {
328b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
329e9192f83SShuai Wang       "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }");
330e9192f83SShuai Wang   const auto Results =
331e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
332e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10"));
333e9192f83SShuai Wang }
334e9192f83SShuai Wang 
335e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ConstOperator) {
336b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
337e9192f83SShuai Wang       "void f() { struct Foo { int operator()() const; }; Foo x; x(); }");
338e9192f83SShuai Wang   const auto Results =
339e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
340e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
341e9192f83SShuai Wang }
342e9192f83SShuai Wang 
343e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, UnresolvedOperator) {
344e517e5cfSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
345e517e5cfSJonas Toth       "template <typename Stream> void input_operator_template() {"
346e517e5cfSJonas Toth       "Stream x; unsigned y = 42;"
347e517e5cfSJonas Toth       "x >> y; }",
348e517e5cfSJonas Toth       {"-fno-delayed-template-parsing"});
349e517e5cfSJonas Toth   const auto Results =
350e517e5cfSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
351e517e5cfSJonas Toth   EXPECT_TRUE(isMutated(Results, AST.get()));
352e517e5cfSJonas Toth }
353e517e5cfSJonas Toth 
354a3d76b3fSJulian Schmidt TEST(ExprMutationAnalyzerTest, DependentOperatorWithNonDependentOperand) {
355a3d76b3fSJulian Schmidt   // gh57297
356a3d76b3fSJulian Schmidt   // The expression to check may not be the dependent operand in a dependent
357a3d76b3fSJulian Schmidt   // operator.
358a3d76b3fSJulian Schmidt 
359a3d76b3fSJulian Schmidt   // Explicitly not declaring a (templated) stream operator
360a3d76b3fSJulian Schmidt   // so the `<<` is a `binaryOperator` with a dependent type.
361a3d76b3fSJulian Schmidt   const auto AST = buildASTFromCodeWithArgs(
362a3d76b3fSJulian Schmidt       "struct Stream { };"
363a3d76b3fSJulian Schmidt       "template <typename T> void f() { T t; Stream x; x << t; }",
364a3d76b3fSJulian Schmidt       {"-fno-delayed-template-parsing"});
365a3d76b3fSJulian Schmidt   const auto Results =
366a3d76b3fSJulian Schmidt       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
367a3d76b3fSJulian Schmidt   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x << t"));
368a3d76b3fSJulian Schmidt }
369a3d76b3fSJulian Schmidt 
3709f8ccf50SJulian Schmidt TEST(ExprMutationAnalyzerTest, FoldExpression) {
3719f8ccf50SJulian Schmidt   // gh70323
3729f8ccf50SJulian Schmidt   // A fold expression may contain `Exp` as it's initializer.
3739f8ccf50SJulian Schmidt   // We don't know if the operator modifies `Exp` because the
3749f8ccf50SJulian Schmidt   // operator is type dependent due to the parameter pack.
3759f8ccf50SJulian Schmidt   auto AST = buildASTFromCodeWithArgs(
3769f8ccf50SJulian Schmidt       "struct Stream {};"
3779f8ccf50SJulian Schmidt       "template <typename... Args> void concatenate(Args... args) "
3789f8ccf50SJulian Schmidt       "{ Stream x; (x << ... << args); }",
3799f8ccf50SJulian Schmidt       {"-fno-delayed-template-parsing"});
3809f8ccf50SJulian Schmidt   auto Results =
3819f8ccf50SJulian Schmidt       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
3829f8ccf50SJulian Schmidt   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(x << ... << args)"));
3839f8ccf50SJulian Schmidt 
3849f8ccf50SJulian Schmidt   AST = buildASTFromCodeWithArgs(
3859f8ccf50SJulian Schmidt       "struct Stream {};"
3869f8ccf50SJulian Schmidt       "template <typename... Args> void concatenate(Args... args) "
3879f8ccf50SJulian Schmidt       "{ Stream x; (args << ... << x); }",
3889f8ccf50SJulian Schmidt       {"-fno-delayed-template-parsing"});
3899f8ccf50SJulian Schmidt   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
3909f8ccf50SJulian Schmidt   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(args << ... << x)"));
3919f8ccf50SJulian Schmidt 
3929f8ccf50SJulian Schmidt   AST = buildASTFromCodeWithArgs(
3939f8ccf50SJulian Schmidt       "struct Stream {};"
3949f8ccf50SJulian Schmidt       "template <typename... Args> void concatenate(Args... args) "
3959f8ccf50SJulian Schmidt       "{ Stream x; (..., (x << args)); }",
3969f8ccf50SJulian Schmidt       {"-fno-delayed-template-parsing"});
3979f8ccf50SJulian Schmidt   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
3989f8ccf50SJulian Schmidt   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x << args"));
3999f8ccf50SJulian Schmidt }
4009f8ccf50SJulian Schmidt 
401e517e5cfSJonas Toth // Section: expression as call argument
402e517e5cfSJonas Toth 
403e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ByValueArgument) {
404b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void g(int); void f() { int x; g(x); }");
405e9192f83SShuai Wang   auto Results =
406e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
407e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
408e9192f83SShuai Wang 
409b81bcb3aSShuai Wang   AST = buildASTFromCode("void g(int*); void f() { int* x; g(x); }");
410e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
411e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
412e9192f83SShuai Wang 
413b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int* IntPtr;"
414e9192f83SShuai Wang                          "void g(IntPtr); void f() { int* x; g(x); }");
415e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
416e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
417e9192f83SShuai Wang 
418b81bcb3aSShuai Wang   AST = buildASTFromCode(
41966908022SShuai Wang       "struct A {}; A operator+(A, int); void f() { A x; x + 1; }");
420e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
421e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
422e9192f83SShuai Wang 
423b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(int); }; int x; A y(x); }");
424e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
425e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
426e9192f83SShuai Wang 
427b81bcb3aSShuai Wang   AST = buildASTFromCode("struct A { A(); A& operator=(A); };"
428b81bcb3aSShuai Wang                          "void f() { A x, y; y = x; }");
429e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
430e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
43186e5cb0eSShuai Wang 
43286e5cb0eSShuai Wang   AST = buildASTFromCode(
43386e5cb0eSShuai Wang       "template <int> struct A { A(); A(const A&); static void mf(A) {} };"
43486e5cb0eSShuai Wang       "void f() { A<0> x; A<0>::mf(x); }");
43586e5cb0eSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
43686e5cb0eSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
437e9192f83SShuai Wang }
438e9192f83SShuai Wang 
439e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ByConstValueArgument) {
440b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void g(const int); void f() { int x; g(x); }");
441e9192f83SShuai Wang   auto Results =
442e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
443e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
444e9192f83SShuai Wang 
445b81bcb3aSShuai Wang   AST = buildASTFromCode("void g(int* const); void f() { int* x; g(x); }");
446e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
447e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
448e9192f83SShuai Wang 
449b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int* const CIntPtr;"
450e9192f83SShuai Wang                          "void g(CIntPtr); void f() { int* x; g(x); }");
451e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
452e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
453e9192f83SShuai Wang 
454b81bcb3aSShuai Wang   AST = buildASTFromCode(
45566908022SShuai Wang       "struct A {}; A operator+(const A, int); void f() { A x; x + 1; }");
456e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
457e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
458e9192f83SShuai Wang 
459b81bcb3aSShuai Wang   AST = buildASTFromCode(
460e9192f83SShuai Wang       "void f() { struct A { A(const int); }; int x; A y(x); }");
461e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
462e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
46386e5cb0eSShuai Wang 
46486e5cb0eSShuai Wang   AST = buildASTFromCode("template <int> struct A { A(); A(const A&);"
46586e5cb0eSShuai Wang                          "static void mf(const A&) {} };"
46686e5cb0eSShuai Wang                          "void f() { A<0> x; A<0>::mf(x); }");
46786e5cb0eSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
46886e5cb0eSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
469e9192f83SShuai Wang }
470e9192f83SShuai Wang 
471e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) {
472b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void g(int&); void f() { int x; g(x); }");
473e9192f83SShuai Wang   auto Results =
474e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
475e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
476e9192f83SShuai Wang 
477b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int& IntRef;"
478e9192f83SShuai Wang                          "void g(IntRef); void f() { int x; g(x); }");
479e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
480e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
481e9192f83SShuai Wang 
482b81bcb3aSShuai Wang   AST = buildASTFromCode("template <class T> using TRef = T&;"
483e9192f83SShuai Wang                          "void g(TRef<int>); void f() { int x; g(x); }");
484e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
485e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
486e9192f83SShuai Wang 
487b81bcb3aSShuai Wang   AST = buildASTFromCode(
488e9192f83SShuai Wang       "template <class T> struct identity { using type = T; };"
489e9192f83SShuai Wang       "template <class T, class U = T&> void g(typename identity<U>::type);"
490e9192f83SShuai Wang       "void f() { int x; g<int>(x); }");
491e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
492e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g<int>(x)"));
493e9192f83SShuai Wang 
494b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int* IntPtr;"
495e9192f83SShuai Wang                          "void g(IntPtr&); void f() { int* x; g(x); }");
496e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
497e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
498e9192f83SShuai Wang 
499b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int* IntPtr; typedef IntPtr& IntPtrRef;"
500e9192f83SShuai Wang                          "void g(IntPtrRef); void f() { int* x; g(x); }");
501e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
502e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
503e9192f83SShuai Wang 
504b81bcb3aSShuai Wang   AST = buildASTFromCode(
50566908022SShuai Wang       "struct A {}; A operator+(A&, int); void f() { A x; x + 1; }");
506e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
507e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1"));
508e9192f83SShuai Wang 
509b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(int&); }; int x; A y(x); }");
510e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
511e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
512e9192f83SShuai Wang 
513b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(); A(A&); }; A x; A y(x); }");
514e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
515e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
51686e5cb0eSShuai Wang 
51786e5cb0eSShuai Wang   AST = buildASTFromCode(
51886e5cb0eSShuai Wang       "template <int> struct A { A(); A(const A&); static void mf(A&) {} };"
51986e5cb0eSShuai Wang       "void f() { A<0> x; A<0>::mf(x); }");
52086e5cb0eSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
52186e5cb0eSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("A<0>::mf(x)"));
522e9192f83SShuai Wang }
523e9192f83SShuai Wang 
524e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, ByNonConstRefArgumentFunctionTypeDependent) {
525e517e5cfSJonas Toth   auto AST = buildASTFromCodeWithArgs(
526e517e5cfSJonas Toth       "enum MyEnum { foo, bar };"
527e517e5cfSJonas Toth       "void tryParser(unsigned& first, MyEnum Type) { first++, (void)Type; }"
528e517e5cfSJonas Toth       "template <MyEnum Type> void parse() {"
529e517e5cfSJonas Toth       "  auto parser = [](unsigned& first) { first++; tryParser(first, Type); "
530e517e5cfSJonas Toth       "};"
531e517e5cfSJonas Toth       "  unsigned x = 42;"
532e517e5cfSJonas Toth       "  parser(x);"
533e517e5cfSJonas Toth       "}",
534e517e5cfSJonas Toth       {"-fno-delayed-template-parsing"});
535e517e5cfSJonas Toth   auto Results =
536e517e5cfSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
537e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("parser(x)"));
538e517e5cfSJonas Toth }
539e517e5cfSJonas Toth 
540e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ByConstRefArgument) {
541b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void g(const int&); void f() { int x; g(x); }");
542e9192f83SShuai Wang   auto Results =
543e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
544e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
545e9192f83SShuai Wang 
546b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef const int& CIntRef;"
547e9192f83SShuai Wang                          "void g(CIntRef); void f() { int x; g(x); }");
548e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
549e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
550e9192f83SShuai Wang 
551b81bcb3aSShuai Wang   AST = buildASTFromCode("template <class T> using CTRef = const T&;"
552e9192f83SShuai Wang                          "void g(CTRef<int>); void f() { int x; g(x); }");
553e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
554e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
555e9192f83SShuai Wang 
556b81bcb3aSShuai Wang   AST =
557b81bcb3aSShuai Wang       buildASTFromCode("template <class T> struct identity { using type = T; };"
558e9192f83SShuai Wang                        "template <class T, class U = const T&>"
559e9192f83SShuai Wang                        "void g(typename identity<U>::type);"
560e9192f83SShuai Wang                        "void f() { int x; g<int>(x); }");
561e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
562e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
563e9192f83SShuai Wang 
564b81bcb3aSShuai Wang   AST = buildASTFromCode(
56566908022SShuai Wang       "struct A {}; A operator+(const A&, int); void f() { A x; x + 1; }");
566e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
567e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
568e9192f83SShuai Wang 
569b81bcb3aSShuai Wang   AST = buildASTFromCode(
570e9192f83SShuai Wang       "void f() { struct A { A(const int&); }; int x; A y(x); }");
571e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
572e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
573e9192f83SShuai Wang 
574b81bcb3aSShuai Wang   AST = buildASTFromCode(
575e9192f83SShuai Wang       "void f() { struct A { A(); A(const A&); }; A x; A y(x); }");
576e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
577e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
578e9192f83SShuai Wang }
579e9192f83SShuai Wang 
580e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ByNonConstRRefArgument) {
581b81bcb3aSShuai Wang   auto AST = buildASTFromCode(
582e9192f83SShuai Wang       "void g(int&&); void f() { int x; g(static_cast<int &&>(x)); }");
583e9192f83SShuai Wang   auto Results =
584e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
585e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
586e9192f83SShuai Wang               ElementsAre("g(static_cast<int &&>(x))"));
587e9192f83SShuai Wang 
58866908022SShuai Wang   AST = buildASTFromCode("struct A {}; A operator+(A&&, int);"
589b81bcb3aSShuai Wang                          "void f() { A x; static_cast<A &&>(x) + 1; }");
590e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
591e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
592e9192f83SShuai Wang               ElementsAre("static_cast<A &&>(x) + 1"));
593e9192f83SShuai Wang 
594b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(int&&); }; "
595e9192f83SShuai Wang                          "int x; A y(static_cast<int &&>(x)); }");
596e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
597e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
598e9192f83SShuai Wang               ElementsAre("static_cast<int &&>(x)"));
599e9192f83SShuai Wang 
600b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(); A(A&&); }; "
601e9192f83SShuai Wang                          "A x; A y(static_cast<A &&>(x)); }");
602e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
603e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
604e9192f83SShuai Wang               ElementsAre("static_cast<A &&>(x)"));
605e9192f83SShuai Wang }
606e9192f83SShuai Wang 
607e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ByConstRRefArgument) {
608b81bcb3aSShuai Wang   auto AST = buildASTFromCode(
609e9192f83SShuai Wang       "void g(const int&&); void f() { int x; g(static_cast<int&&>(x)); }");
610e9192f83SShuai Wang   auto Results =
611e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
612e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
613e517e5cfSJonas Toth               ElementsAre("static_cast<int &&>(x)"));
614e9192f83SShuai Wang 
61566908022SShuai Wang   AST = buildASTFromCode("struct A {}; A operator+(const A&&, int);"
616b81bcb3aSShuai Wang                          "void f() { A x; static_cast<A&&>(x) + 1; }");
617e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
618e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
619e517e5cfSJonas Toth               ElementsAre("static_cast<A &&>(x)"));
620e9192f83SShuai Wang 
621b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(const int&&); }; "
622e9192f83SShuai Wang                          "int x; A y(static_cast<int&&>(x)); }");
623e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
624e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
625e517e5cfSJonas Toth               ElementsAre("static_cast<int &&>(x)"));
626e9192f83SShuai Wang 
627b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { struct A { A(); A(const A&&); }; "
628e9192f83SShuai Wang                          "A x; A y(static_cast<A&&>(x)); }");
629e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
630e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
631e517e5cfSJonas Toth               ElementsAre("static_cast<A &&>(x)"));
632e9192f83SShuai Wang }
633e9192f83SShuai Wang 
6348fd32b96SClement Courbet // Section: bindings.
6358fd32b96SClement Courbet 
6368fd32b96SClement Courbet TEST(ExprMutationAnalyzerTest, BindingModifies) {
6378fd32b96SClement Courbet   const auto AST =
6388fd32b96SClement Courbet       buildASTFromCode("struct Point { int x; int y; };"
6398fd32b96SClement Courbet                        "void mod(int&);"
6408fd32b96SClement Courbet                        "void f(Point p) { auto& [x, y] = p; mod(x); }");
6418fd32b96SClement Courbet   const auto Results =
6428fd32b96SClement Courbet       match(withEnclosingCompound(declRefTo("p")), AST->getASTContext());
6438fd32b96SClement Courbet   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x", "mod(x)"));
6448fd32b96SClement Courbet }
6458fd32b96SClement Courbet 
6468fd32b96SClement Courbet TEST(ExprMutationAnalyzerTest, BindingDoesNotModify) {
6478fd32b96SClement Courbet   const auto AST = buildASTFromCode("struct Point { int x; int y; };"
6488fd32b96SClement Courbet                                     "void f(Point p) { auto& [x, y] = p; x; }");
6498fd32b96SClement Courbet   const auto Results =
6508fd32b96SClement Courbet       match(withEnclosingCompound(declRefTo("p")), AST->getASTContext());
6518fd32b96SClement Courbet   EXPECT_FALSE(isMutated(Results, AST.get()));
6528fd32b96SClement Courbet }
6538fd32b96SClement Courbet 
654e517e5cfSJonas Toth // section: explicit std::move and std::forward testing
655e517e5cfSJonas Toth 
656e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, Move) {
657b81bcb3aSShuai Wang   auto AST = buildASTFromCode(StdRemoveReference + StdMove +
658e9192f83SShuai Wang                               "void f() { struct A {}; A x; std::move(x); }");
6594305993cSShuai Wang   auto Results =
660e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6614305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
6624305993cSShuai Wang 
663b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
6644305993cSShuai Wang                          "void f() { struct A {}; A x, y; std::move(x) = y; }");
6654305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6664305993cSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x) = y"));
6674305993cSShuai Wang 
668b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
6694305993cSShuai Wang                          "void f() { int x, y; y = std::move(x); }");
6704305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6714305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
6724305993cSShuai Wang 
673b81bcb3aSShuai Wang   AST =
674b81bcb3aSShuai Wang       buildASTFromCode(StdRemoveReference + StdMove +
6754305993cSShuai Wang                        "struct S { S(); S(const S&); S& operator=(const S&); };"
6764305993cSShuai Wang                        "void f() { S x, y; y = std::move(x); }");
6774305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6784305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
6794305993cSShuai Wang 
680b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
6814305993cSShuai Wang                          "struct S { S(); S(S&&); S& operator=(S&&); };"
6824305993cSShuai Wang                          "void f() { S x, y; y = std::move(x); }");
6834305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6844305993cSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)"));
6854305993cSShuai Wang 
686b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
6874305993cSShuai Wang                          "struct S { S(); S(const S&); S(S&&);"
6884305993cSShuai Wang                          "S& operator=(const S&); S& operator=(S&&); };"
6894305993cSShuai Wang                          "void f() { S x, y; y = std::move(x); }");
6904305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6914305993cSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)"));
6924305993cSShuai Wang 
693b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
6944305993cSShuai Wang                          "struct S { S(); S(const S&); S(S&&);"
6954305993cSShuai Wang                          "S& operator=(const S&); S& operator=(S&&); };"
6964305993cSShuai Wang                          "void f() { const S x; S y; y = std::move(x); }");
6974305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
6984305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
6994305993cSShuai Wang 
700b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
701b81bcb3aSShuai Wang                          "struct S { S(); S& operator=(S); };"
7024305993cSShuai Wang                          "void f() { S x, y; y = std::move(x); }");
7034305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
7044305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
7054305993cSShuai Wang 
706b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdMove +
7074305993cSShuai Wang                          "struct S{}; void f() { S x, y; y = std::move(x); }");
7084305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
7094305993cSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)"));
7104305993cSShuai Wang 
711b81bcb3aSShuai Wang   AST = buildASTFromCode(
7124305993cSShuai Wang       StdRemoveReference + StdMove +
7134305993cSShuai Wang       "struct S{}; void f() { const S x; S y; y = std::move(x); }");
7144305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
7154305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
716e9192f83SShuai Wang }
717e9192f83SShuai Wang 
718e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, Forward) {
719b81bcb3aSShuai Wang   auto AST =
720b81bcb3aSShuai Wang       buildASTFromCode(StdRemoveReference + StdForward +
721e9192f83SShuai Wang                        "void f() { struct A {}; A x; std::forward<A &>(x); }");
7224305993cSShuai Wang   auto Results =
723e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
7244305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
7254305993cSShuai Wang 
726b81bcb3aSShuai Wang   AST = buildASTFromCode(
7274305993cSShuai Wang       StdRemoveReference + StdForward +
7284305993cSShuai Wang       "void f() { struct A {}; A x, y; std::forward<A &>(x) = y; }");
7294305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
730e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
7314305993cSShuai Wang               ElementsAre("std::forward<A &>(x) = y"));
732e9192f83SShuai Wang }
733e9192f83SShuai Wang 
734e517e5cfSJonas Toth // section: template constellations that prohibit reasoning about modifications
735e517e5cfSJonas Toth //          as it depends on instantiations.
736e517e5cfSJonas Toth 
737e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, CallUnresolved) {
738b81bcb3aSShuai Wang   auto AST =
739b81bcb3aSShuai Wang       buildASTFromCodeWithArgs("template <class T> void f() { T x; g(x); }",
740e9192f83SShuai Wang                                {"-fno-delayed-template-parsing"});
741e9192f83SShuai Wang   auto Results =
742e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
743e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
744e9192f83SShuai Wang 
745b81bcb3aSShuai Wang   AST =
746b81bcb3aSShuai Wang       buildASTFromCodeWithArgs("template <int N> void f() { char x[N]; g(x); }",
747e9192f83SShuai Wang                                {"-fno-delayed-template-parsing"});
748e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
749e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
750e9192f83SShuai Wang 
751b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
752e9192f83SShuai Wang       "template <class T> void f(T t) { int x; g(t, x); }",
753e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
754e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
755e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(t, x)"));
756e9192f83SShuai Wang 
757b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
758e9192f83SShuai Wang       "template <class T> void f(T t) { int x; t.mf(x); }",
759e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
760e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
761e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("t.mf(x)"));
762e9192f83SShuai Wang 
763b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
764e9192f83SShuai Wang       "template <class T> struct S;"
765e9192f83SShuai Wang       "template <class T> void f() { S<T> s; int x; s.mf(x); }",
766e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
767e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
768e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)"));
769e9192f83SShuai Wang 
770b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
771e9192f83SShuai Wang       "struct S { template <class T> void mf(); };"
772e9192f83SShuai Wang       "template <class T> void f(S s) { int x; s.mf<T>(x); }",
773e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
774e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
775e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf<T>(x)"));
776e9192f83SShuai Wang 
777b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs("template <class F>"
778e9192f83SShuai Wang                                  "void g(F f) { int x; f(x); } ",
779e9192f83SShuai Wang                                  {"-fno-delayed-template-parsing"});
780e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
781e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f(x)"));
782e9192f83SShuai Wang 
783b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
784e9192f83SShuai Wang       "template <class T> void f() { int x; (void)T(x); }",
785e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
786e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
787e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("T(x)"));
788e9192f83SShuai Wang }
789e9192f83SShuai Wang 
790e517e5cfSJonas Toth // section: return values
791e517e5cfSJonas Toth 
792e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ReturnAsValue) {
793b81bcb3aSShuai Wang   auto AST = buildASTFromCode("int f() { int x; return x; }");
794e9192f83SShuai Wang   auto Results =
795e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
796e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
797e9192f83SShuai Wang 
798b81bcb3aSShuai Wang   AST = buildASTFromCode("int* f() { int* x; return x; }");
799e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
800e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
801e9192f83SShuai Wang 
802b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int* IntPtr;"
803e9192f83SShuai Wang                          "IntPtr f() { int* x; return x; }");
804e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
805e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
806e9192f83SShuai Wang }
807e9192f83SShuai Wang 
808e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) {
809b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("int& f() { int x; return x; }");
810e9192f83SShuai Wang   const auto Results =
811e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
812e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;"));
813e9192f83SShuai Wang }
814e9192f83SShuai Wang 
815e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) {
816b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("const int& f() { int x; return x; }");
817e9192f83SShuai Wang   const auto Results =
818e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
819e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
820e9192f83SShuai Wang }
821e9192f83SShuai Wang 
822e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRRef) {
823b81bcb3aSShuai Wang   const auto AST =
824b81bcb3aSShuai Wang       buildASTFromCode("int&& f() { int x; return static_cast<int &&>(x); }");
825e9192f83SShuai Wang   const auto Results =
826e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
827e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
828e517e5cfSJonas Toth               ElementsAre("static_cast<int &&>(x)"));
829e9192f83SShuai Wang }
830e9192f83SShuai Wang 
831e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ReturnAsConstRRef) {
832b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
833e9192f83SShuai Wang       "const int&& f() { int x; return static_cast<int&&>(x); }");
834e9192f83SShuai Wang   const auto Results =
835e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
836e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
837e517e5cfSJonas Toth               ElementsAre("static_cast<int &&>(x)"));
838e9192f83SShuai Wang }
839e9192f83SShuai Wang 
840e517e5cfSJonas Toth // section: taking the address of a variable and pointers
841e517e5cfSJonas Toth 
842e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, TakeAddress) {
843b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void g(int*); void f() { int x; g(&x); }");
844e9192f83SShuai Wang   const auto Results =
845e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
846e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x"));
847e9192f83SShuai Wang }
848e9192f83SShuai Wang 
849e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ArrayToPointerDecay) {
850e9192f83SShuai Wang   const auto AST =
851b81bcb3aSShuai Wang       buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }");
852e9192f83SShuai Wang   const auto Results =
853e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
854e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
855e9192f83SShuai Wang }
856e9192f83SShuai Wang 
857e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, TemplateWithArrayToPointerDecay) {
858b81bcb3aSShuai Wang   const auto AST = buildASTFromCodeWithArgs(
859e9192f83SShuai Wang       "template <typename T> struct S { static constexpr int v = 8; };"
860e9192f83SShuai Wang       "template <> struct S<int> { static constexpr int v = 4; };"
861e9192f83SShuai Wang       "void g(char*);"
862e9192f83SShuai Wang       "template <typename T> void f() { char x[S<T>::v]; g(x); }"
863e9192f83SShuai Wang       "template <> void f<int>() { char y[S<int>::v]; g(y); }",
864e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
865e9192f83SShuai Wang   const auto ResultsX =
866e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
867e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(ResultsX, AST.get()), ElementsAre("g(x)"));
868e9192f83SShuai Wang   const auto ResultsY =
869e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
870e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y"));
871e9192f83SShuai Wang }
872e9192f83SShuai Wang 
873e517e5cfSJonas Toth // section: special case: all created references are non-mutating themself
874e517e5cfSJonas Toth //          and therefore all become 'const'/the value is not modified!
875e517e5cfSJonas Toth 
876e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, FollowRefModified) {
877b81bcb3aSShuai Wang   auto AST = buildASTFromCode(
878e9192f83SShuai Wang       "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; "
879e9192f83SShuai Wang       "int& r3 = r2; r3 = 10; }");
880e9192f83SShuai Wang   auto Results =
881e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
882e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
883e9192f83SShuai Wang               ElementsAre("r0", "r1", "r2", "r3", "r3 = 10"));
884e9192f83SShuai Wang 
885b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int& IntRefX;"
886e9192f83SShuai Wang                          "using IntRefY = int&;"
887e9192f83SShuai Wang                          "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;"
888e9192f83SShuai Wang                          "decltype((x)) r2 = r1; r2 = 10; }");
889e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
890e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
891e9192f83SShuai Wang               ElementsAre("r0", "r1", "r2", "r2 = 10"));
892e9192f83SShuai Wang }
893e9192f83SShuai Wang 
894e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, FollowRefNotModified) {
895b81bcb3aSShuai Wang   auto AST = buildASTFromCode(
896e9192f83SShuai Wang       "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; "
897e9192f83SShuai Wang       "int& r3 = r2; int& r4 = r3; int& r5 = r4;}");
898e9192f83SShuai Wang   auto Results =
899e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
900e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
901e9192f83SShuai Wang 
902b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { int x; int& r0 = x; const int& r1 = r0;}");
903e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
904e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
905e9192f83SShuai Wang 
906b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef const int& CIntRefX;"
907e9192f83SShuai Wang                          "using CIntRefY = const int&;"
908e9192f83SShuai Wang                          "void f() { int x; int& r0 = x; CIntRefX r1 = r0;"
909e9192f83SShuai Wang                          "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}");
910e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
911e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
912e9192f83SShuai Wang }
913e9192f83SShuai Wang 
914e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) {
915b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
916e9192f83SShuai Wang       "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }");
917e9192f83SShuai Wang   const auto Results =
918e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
919e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10"));
920e9192f83SShuai Wang }
921e9192f83SShuai Wang 
922e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, FollowConditionalRefNotModified) {
923b81bcb3aSShuai Wang   const auto AST =
924b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x, y; bool b; int& r = b ? x : y; }");
925e9192f83SShuai Wang   const auto Results =
926e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
927e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
928e9192f83SShuai Wang }
929e9192f83SShuai Wang 
930cb98b707SShuai Wang TEST(ExprMutationAnalyzerTest, FollowFuncArgModified) {
931b81bcb3aSShuai Wang   auto AST = buildASTFromCode("template <class T> void g(T&& t) { t = 10; }"
932cb98b707SShuai Wang                               "void f() { int x; g(x); }");
933cb98b707SShuai Wang   auto Results =
934cb98b707SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
935cb98b707SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
936cb98b707SShuai Wang 
937b81bcb3aSShuai Wang   AST = buildASTFromCode(
938cb98b707SShuai Wang       "void h(int&);"
939cb98b707SShuai Wang       "template <class... Args> void g(Args&&... args) { h(args...); }"
940cb98b707SShuai Wang       "void f() { int x; g(x); }");
941cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
942cb98b707SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
943cb98b707SShuai Wang 
944b81bcb3aSShuai Wang   AST = buildASTFromCode(
945cb98b707SShuai Wang       "void h(int&, int);"
946cb98b707SShuai Wang       "template <class... Args> void g(Args&&... args) { h(args...); }"
947cb98b707SShuai Wang       "void f() { int x, y; g(x, y); }");
948cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
949cb98b707SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x, y)"));
950cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
951cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
952cb98b707SShuai Wang 
953b81bcb3aSShuai Wang   AST = buildASTFromCode(
954cb98b707SShuai Wang       "void h(int, int&);"
955cb98b707SShuai Wang       "template <class... Args> void g(Args&&... args) { h(args...); }"
956cb98b707SShuai Wang       "void f() { int x, y; g(y, x); }");
957cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
958cb98b707SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(y, x)"));
959cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
960cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
961cb98b707SShuai Wang 
962b81bcb3aSShuai Wang   AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t = 10; } };"
963cb98b707SShuai Wang                          "void f() { int x; S s(x); }");
964cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
965cb98b707SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
966cb98b707SShuai Wang 
967b81bcb3aSShuai Wang   AST = buildASTFromCode(
968cb98b707SShuai Wang       "struct S { template <class T> S(T&& t) : m(++t) { } int m; };"
969cb98b707SShuai Wang       "void f() { int x; S s(x); }");
970cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
971cb98b707SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
9724305993cSShuai Wang 
97386e5cb0eSShuai Wang   AST = buildASTFromCode("template <class U> struct S {"
97486e5cb0eSShuai Wang                          "template <class T> S(T&& t) : m(++t) { } U m; };"
97586e5cb0eSShuai Wang                          "void f() { int x; S<int> s(x); }");
97686e5cb0eSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
97786e5cb0eSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
97886e5cb0eSShuai Wang 
979b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdForward +
9804305993cSShuai Wang                          "template <class... Args> void u(Args&...);"
9814305993cSShuai Wang                          "template <class... Args> void h(Args&&... args)"
9824305993cSShuai Wang                          "{ u(std::forward<Args>(args)...); }"
9834305993cSShuai Wang                          "template <class... Args> void g(Args&&... args)"
9844305993cSShuai Wang                          "{ h(std::forward<Args>(args)...); }"
9854305993cSShuai Wang                          "void f() { int x; g(x); }");
9864305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
9874305993cSShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
988f40f4fceSCongcong Cai 
989f40f4fceSCongcong Cai   AST = buildASTFromCode(
990f40f4fceSCongcong Cai       StdRemoveReference + StdForward +
991f40f4fceSCongcong Cai       "template <class T> void f1(T &&a);"
992f40f4fceSCongcong Cai       "template <class T> void f2(T &&a);"
993f40f4fceSCongcong Cai       "template <class T> void f1(T &&a) { f2<T>(std::forward<T>(a)); }"
994f40f4fceSCongcong Cai       "template <class T> void f2(T &&a) { f1<T>(std::forward<T>(a)); }"
995f40f4fceSCongcong Cai       "void f() { int x; f1(x); }");
996f40f4fceSCongcong Cai   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
997f40f4fceSCongcong Cai   EXPECT_FALSE(isMutated(Results, AST.get()));
998f40f4fceSCongcong Cai 
999f40f4fceSCongcong Cai   AST = buildASTFromCode(
1000f40f4fceSCongcong Cai       StdRemoveReference + StdForward +
1001f40f4fceSCongcong Cai       "template <class T> void f1(T &&a);"
1002f40f4fceSCongcong Cai       "template <class T> void f2(T &&a);"
1003f40f4fceSCongcong Cai       "template <class T> void f1(T &&a) { f2<T>(std::forward<T>(a)); }"
1004f40f4fceSCongcong Cai       "template <class T> void f2(T &&a) { f1<T>(std::forward<T>(a)); a++; }"
1005f40f4fceSCongcong Cai       "void f() { int x; f1(x); }");
1006f40f4fceSCongcong Cai   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1007f40f4fceSCongcong Cai   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f1(x)"));
1008f40f4fceSCongcong Cai 
1009f40f4fceSCongcong Cai   AST = buildASTFromCode(
1010f40f4fceSCongcong Cai       StdRemoveReference + StdForward +
1011f40f4fceSCongcong Cai       "template <class T> void f1(T &&a);"
1012f40f4fceSCongcong Cai       "template <class T> void f2(T &&a);"
1013f40f4fceSCongcong Cai       "template <class T> void f1(T &&a) { f2<T>(std::forward<T>(a)); a++; }"
1014f40f4fceSCongcong Cai       "template <class T> void f2(T &&a) { f1<T>(std::forward<T>(a)); }"
1015f40f4fceSCongcong Cai       "void f() { int x; f1(x); }");
1016f40f4fceSCongcong Cai   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1017f40f4fceSCongcong Cai   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f1(x)"));
1018cb98b707SShuai Wang }
1019cb98b707SShuai Wang 
1020cb98b707SShuai Wang TEST(ExprMutationAnalyzerTest, FollowFuncArgNotModified) {
1021b81bcb3aSShuai Wang   auto AST = buildASTFromCode("template <class T> void g(T&&) {}"
1022cb98b707SShuai Wang                               "void f() { int x; g(x); }");
1023cb98b707SShuai Wang   auto Results =
1024cb98b707SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1025cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1026cb98b707SShuai Wang 
1027b81bcb3aSShuai Wang   AST = buildASTFromCode("template <class T> void g(T&& t) { t; }"
1028cb98b707SShuai Wang                          "void f() { int x; g(x); }");
1029cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1030cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1031cb98b707SShuai Wang 
1032b81bcb3aSShuai Wang   AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}"
1033cb98b707SShuai Wang                          "void f() { int x; g(x); }");
1034cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1035cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1036cb98b707SShuai Wang 
1037b81bcb3aSShuai Wang   AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}"
1038cb98b707SShuai Wang                          "void f() { int y, x; g(y, x); }");
1039cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1040cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1041cb98b707SShuai Wang 
1042b81bcb3aSShuai Wang   AST = buildASTFromCode(
1043cb98b707SShuai Wang       "void h(int, int&);"
1044cb98b707SShuai Wang       "template <class... Args> void g(Args&&... args) { h(args...); }"
1045cb98b707SShuai Wang       "void f() { int x, y; g(x, y); }");
1046cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1047cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1048cb98b707SShuai Wang 
1049b81bcb3aSShuai Wang   AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t; } };"
1050cb98b707SShuai Wang                          "void f() { int x; S s(x); }");
1051cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1052cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1053cb98b707SShuai Wang 
1054b81bcb3aSShuai Wang   AST = buildASTFromCode(
1055cb98b707SShuai Wang       "struct S { template <class T> S(T&& t) : m(t) { } int m; };"
1056cb98b707SShuai Wang       "void f() { int x; S s(x); }");
1057cb98b707SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1058cb98b707SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
10594305993cSShuai Wang 
106086e5cb0eSShuai Wang   AST = buildASTFromCode("template <class U> struct S {"
106186e5cb0eSShuai Wang                          "template <class T> S(T&& t) : m(t) { } U m; };"
106286e5cb0eSShuai Wang                          "void f() { int x; S<int> s(x); }");
106386e5cb0eSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
106486e5cb0eSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
106586e5cb0eSShuai Wang 
1066b81bcb3aSShuai Wang   AST = buildASTFromCode(StdRemoveReference + StdForward +
10674305993cSShuai Wang                          "template <class... Args> void u(Args...);"
10684305993cSShuai Wang                          "template <class... Args> void h(Args&&... args)"
10694305993cSShuai Wang                          "{ u(std::forward<Args>(args)...); }"
10704305993cSShuai Wang                          "template <class... Args> void g(Args&&... args)"
10714305993cSShuai Wang                          "{ h(std::forward<Args>(args)...); }"
10724305993cSShuai Wang                          "void f() { int x; g(x); }");
10734305993cSShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
10744305993cSShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1075cb98b707SShuai Wang }
1076cb98b707SShuai Wang 
1077e517e5cfSJonas Toth // section: builtin arrays
1078e517e5cfSJonas Toth 
1079e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ArrayElementModified) {
1080b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x[2]; x[0] = 10; }");
1081e9192f83SShuai Wang   const auto Results =
1082e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1083e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10"));
1084e9192f83SShuai Wang }
1085e9192f83SShuai Wang 
1086e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) {
1087b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x[2]; x[0]; }");
1088e9192f83SShuai Wang   const auto Results =
1089e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1090e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1091e9192f83SShuai Wang }
1092e9192f83SShuai Wang 
1093e517e5cfSJonas Toth // section: member modifications
1094e517e5cfSJonas Toth 
1095e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, NestedMemberModified) {
1096b81bcb3aSShuai Wang   auto AST =
1097b81bcb3aSShuai Wang       buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; "
1098e9192f83SShuai Wang                        "struct C { B vb; }; C x; x.vb.va.vi = 10; }");
1099e9192f83SShuai Wang   auto Results =
1100e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1101e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10"));
1102e9192f83SShuai Wang 
1103b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
1104e9192f83SShuai Wang       "template <class T> void f() { T x; x.y.z = 10; }",
1105e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
1106e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1107e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10"));
1108e9192f83SShuai Wang 
1109b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
1110e9192f83SShuai Wang       "template <class T> struct S;"
1111e9192f83SShuai Wang       "template <class T> void f() { S<T> x; x.y.z = 10; }",
1112e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
1113e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1114e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10"));
1115e9192f83SShuai Wang }
1116e9192f83SShuai Wang 
1117e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, NestedMemberNotModified) {
1118b81bcb3aSShuai Wang   auto AST =
1119b81bcb3aSShuai Wang       buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; "
1120e9192f83SShuai Wang                        "struct C { B vb; }; C x; x.vb.va.vi; }");
1121e9192f83SShuai Wang   auto Results =
1122e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1123e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1124e9192f83SShuai Wang 
1125b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.y.z; }",
1126e9192f83SShuai Wang                                  {"-fno-delayed-template-parsing"});
1127e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1128e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1129e9192f83SShuai Wang 
1130b81bcb3aSShuai Wang   AST =
1131b81bcb3aSShuai Wang       buildASTFromCodeWithArgs("template <class T> struct S;"
1132e9192f83SShuai Wang                                "template <class T> void f() { S<T> x; x.y.z; }",
1133e9192f83SShuai Wang                                {"-fno-delayed-template-parsing"});
1134e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1135e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1136e9192f83SShuai Wang }
1137e9192f83SShuai Wang 
1138e517e5cfSJonas Toth // section: casts
1139e517e5cfSJonas Toth 
1140e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, CastToValue) {
1141e9192f83SShuai Wang   const auto AST =
1142b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x; static_cast<double>(x); }");
1143e9192f83SShuai Wang   const auto Results =
1144e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1145e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1146e9192f83SShuai Wang }
1147e9192f83SShuai Wang 
1148e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, CastToRefModified) {
1149b81bcb3aSShuai Wang   auto AST =
1150b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x; static_cast<int &>(x) = 10; }");
1151e9192f83SShuai Wang   auto Results =
1152e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1153e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
1154e517e5cfSJonas Toth               ElementsAre("static_cast<int &>(x)"));
1155e9192f83SShuai Wang 
1156b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int& IntRef;"
1157e9192f83SShuai Wang                          "void f() { int x; static_cast<IntRef>(x) = 10; }");
1158e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1159e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
1160e517e5cfSJonas Toth               ElementsAre("static_cast<IntRef>(x)"));
1161e9192f83SShuai Wang }
1162e9192f83SShuai Wang 
1163e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, CastToRefNotModified) {
1164e9192f83SShuai Wang   const auto AST =
1165b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x; static_cast<int&>(x); }");
1166e9192f83SShuai Wang   const auto Results =
1167e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1168e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
1169e517e5cfSJonas Toth               ElementsAre("static_cast<int &>(x)"));
1170e9192f83SShuai Wang }
1171e9192f83SShuai Wang 
1172e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, CastToConstRef) {
1173b81bcb3aSShuai Wang   auto AST =
1174b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x; static_cast<const int&>(x); }");
1175e9192f83SShuai Wang   auto Results =
1176e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1177e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1178e9192f83SShuai Wang 
1179b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef const int& CIntRef;"
1180e9192f83SShuai Wang                          "void f() { int x; static_cast<CIntRef>(x); }");
1181e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1182e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1183e9192f83SShuai Wang }
1184e9192f83SShuai Wang 
1185e517e5cfSJonas Toth // section: comma expressions
1186e517e5cfSJonas Toth 
1187e4c0f4a2SCongcong Cai TEST(ExprMutationAnalyzerTest, CommaExprWithAnAssignment) {
1188cdd05f2aSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
1189cdd05f2aSJonas Toth       "void f() { int x; int y; (x, y) = 5; }", {"-Wno-unused-value"});
1190eb39991cSPetar Jovanovic   const auto Results =
1191eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
1192eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1193eb39991cSPetar Jovanovic }
1194eb39991cSPetar Jovanovic 
1195eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) {
1196cdd05f2aSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
1197cdd05f2aSJonas Toth       "void f() { int x; int y; (x, y)++; }", {"-Wno-unused-value"});
1198eb39991cSPetar Jovanovic   const auto Results =
1199eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
1200eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1201eb39991cSPetar Jovanovic }
1202eb39991cSPetar Jovanovic 
1203eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) {
1204cdd05f2aSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
1205cdd05f2aSJonas Toth       "class A { public: int mem; void f() { mem ++; } };"
1206eb39991cSPetar Jovanovic       "void fn() { A o1, o2; (o1, o2).f(); }",
1207eb39991cSPetar Jovanovic       {"-Wno-unused-value"});
1208eb39991cSPetar Jovanovic   const auto Results =
1209eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
1210eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1211eb39991cSPetar Jovanovic }
1212eb39991cSPetar Jovanovic 
1213eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) {
1214cdd05f2aSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
1215cdd05f2aSJonas Toth       "class A { public: int mem; void f() const  { } };"
1216eb39991cSPetar Jovanovic       "void fn() { A o1, o2; (o1, o2).f(); }",
1217eb39991cSPetar Jovanovic       {"-Wno-unused-value"});
1218eb39991cSPetar Jovanovic   const auto Results =
1219eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
1220eb39991cSPetar Jovanovic   EXPECT_FALSE(isMutated(Results, AST.get()));
1221eb39991cSPetar Jovanovic }
1222eb39991cSPetar Jovanovic 
1223eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprWithCallExpr) {
1224eb39991cSPetar Jovanovic   const auto AST =
1225eb39991cSPetar Jovanovic       buildASTFromCodeWithArgs("class A { public: int mem; void f(A &O1) {} };"
1226eb39991cSPetar Jovanovic                                "void fn() { A o1, o2; o2.f((o2, o1)); }",
1227eb39991cSPetar Jovanovic                                {"-Wno-unused-value"});
1228eb39991cSPetar Jovanovic   const auto Results =
1229eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
1230eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1231eb39991cSPetar Jovanovic }
1232eb39991cSPetar Jovanovic 
1233eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprWithCallUnresolved) {
1234eb39991cSPetar Jovanovic   auto AST = buildASTFromCodeWithArgs(
1235eb39991cSPetar Jovanovic       "template <class T> struct S;"
1236eb39991cSPetar Jovanovic       "template <class T> void f() { S<T> s; int x, y; s.mf((y, x)); }",
123715846bb5SReid Kleckner       {"-fno-delayed-template-parsing", "-Wno-unused-value"});
1238eb39991cSPetar Jovanovic   auto Results =
1239eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1240eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1241eb39991cSPetar Jovanovic 
1242eb39991cSPetar Jovanovic   AST = buildASTFromCodeWithArgs(
1243eb39991cSPetar Jovanovic       "template <class T> void f(T t) { int x, y; g(t, (y, x)); }",
124415846bb5SReid Kleckner       {"-fno-delayed-template-parsing", "-Wno-unused-value"});
1245eb39991cSPetar Jovanovic   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1246eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1247eb39991cSPetar Jovanovic }
1248eb39991cSPetar Jovanovic 
1249eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprParmRef) {
1250eb39991cSPetar Jovanovic   const auto AST =
1251eb39991cSPetar Jovanovic       buildASTFromCodeWithArgs("class A { public: int mem;};"
1252eb39991cSPetar Jovanovic                                "extern void fn(A &o1);"
1253eb39991cSPetar Jovanovic                                "void fn2 () { A o1, o2; fn((o2, o1)); } ",
1254eb39991cSPetar Jovanovic                                {"-Wno-unused-value"});
1255eb39991cSPetar Jovanovic   const auto Results =
1256eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
1257eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1258eb39991cSPetar Jovanovic }
1259eb39991cSPetar Jovanovic 
1260eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) {
1261cdd05f2aSJonas Toth   const auto AST = buildASTFromCodeWithArgs("class A { public: int mem;};"
1262eb39991cSPetar Jovanovic                                             "void fn () { A o1, o2;"
1263eb39991cSPetar Jovanovic                                             "void *addr = &(o2, o1); } ",
1264eb39991cSPetar Jovanovic                                             {"-Wno-unused-value"});
1265eb39991cSPetar Jovanovic   const auto Results =
1266eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
1267eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1268eb39991cSPetar Jovanovic }
1269eb39991cSPetar Jovanovic 
1270eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsValue) {
1271eb39991cSPetar Jovanovic   auto AST = buildASTFromCodeWithArgs("int f() { int x, y; return (x, y); }",
1272eb39991cSPetar Jovanovic                                       {"-Wno-unused-value"});
1273eb39991cSPetar Jovanovic   auto Results =
1274eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
1275eb39991cSPetar Jovanovic   EXPECT_FALSE(isMutated(Results, AST.get()));
1276eb39991cSPetar Jovanovic }
1277eb39991cSPetar Jovanovic 
1278e4c0f4a2SCongcong Cai TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsNonConstRef) {
1279cdd05f2aSJonas Toth   const auto AST = buildASTFromCodeWithArgs(
1280cdd05f2aSJonas Toth       "int& f() { int x, y; return (y, x); }", {"-Wno-unused-value"});
1281eb39991cSPetar Jovanovic   const auto Results =
1282eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1283eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1284eb39991cSPetar Jovanovic }
1285eb39991cSPetar Jovanovic 
1286eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprAsArrayToPointerDecay) {
1287eb39991cSPetar Jovanovic   const auto AST =
1288eb39991cSPetar Jovanovic       buildASTFromCodeWithArgs("void g(int*); "
1289eb39991cSPetar Jovanovic                                "void f() { int x[2], y[2]; g((y, x)); }",
1290eb39991cSPetar Jovanovic                                {"-Wno-unused-value"});
1291eb39991cSPetar Jovanovic   const auto Results =
1292eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1293eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1294eb39991cSPetar Jovanovic }
1295eb39991cSPetar Jovanovic 
1296eb39991cSPetar Jovanovic TEST(ExprMutationAnalyzerTest, CommaExprAsUniquePtr) {
1297cdd05f2aSJonas Toth   const std::string UniquePtrDef = "template <class T> struct UniquePtr {"
1298eb39991cSPetar Jovanovic                                    "  UniquePtr();"
1299eb39991cSPetar Jovanovic                                    "  UniquePtr(const UniquePtr&) = delete;"
1300eb39991cSPetar Jovanovic                                    "  T& operator*() const;"
1301eb39991cSPetar Jovanovic                                    "  T* operator->() const;"
1302eb39991cSPetar Jovanovic                                    "};";
1303eb39991cSPetar Jovanovic   const auto AST = buildASTFromCodeWithArgs(
1304eb39991cSPetar Jovanovic       UniquePtrDef + "template <class T> void f() "
1305eb39991cSPetar Jovanovic                      "{ UniquePtr<T> x; UniquePtr<T> y;"
1306eb39991cSPetar Jovanovic                      " (y, x)->mf(); }",
130715846bb5SReid Kleckner       {"-fno-delayed-template-parsing", "-Wno-unused-value"});
1308eb39991cSPetar Jovanovic   const auto Results =
1309eb39991cSPetar Jovanovic       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1310eb39991cSPetar Jovanovic   EXPECT_TRUE(isMutated(Results, AST.get()));
1311eb39991cSPetar Jovanovic }
1312eb39991cSPetar Jovanovic 
1313e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, CommaNestedConditional) {
1314e517e5cfSJonas Toth   const std::string Code = "void f() { int x, y = 42;"
1315e517e5cfSJonas Toth                            " y, (true ? x : y) = 42; }";
1316e517e5cfSJonas Toth   const auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"});
1317e517e5cfSJonas Toth   const auto Results =
1318e517e5cfSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1319e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
1320e517e5cfSJonas Toth               ElementsAre("(true ? x : y) = 42"));
1321e517e5cfSJonas Toth }
1322e517e5cfSJonas Toth 
1323e517e5cfSJonas Toth // section: lambda captures
1324e517e5cfSJonas Toth 
1325e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) {
1326b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }");
1327e9192f83SShuai Wang   const auto Results =
1328e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1329e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1330e9192f83SShuai Wang }
1331e9192f83SShuai Wang 
1332e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) {
1333b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }");
1334e9192f83SShuai Wang   const auto Results =
1335e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1336e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1337e9192f83SShuai Wang }
1338e9192f83SShuai Wang 
1339e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) {
1340b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }");
1341e9192f83SShuai Wang   const auto Results =
1342e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1343e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
1344e9192f83SShuai Wang               ElementsAre(ResultOf(removeSpace, "[&](){x=10;}")));
1345e9192f83SShuai Wang }
1346e9192f83SShuai Wang 
1347e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) {
1348b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }");
1349e9192f83SShuai Wang   const auto Results =
1350e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1351e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()),
1352e9192f83SShuai Wang               ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}")));
1353e9192f83SShuai Wang }
1354e9192f83SShuai Wang 
1355e517e5cfSJonas Toth // section: range-for loops
1356e517e5cfSJonas Toth 
1357e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) {
1358b81bcb3aSShuai Wang   auto AST =
1359b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }");
1360e9192f83SShuai Wang   auto Results =
1361e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1362e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
1363e517e5cfSJonas Toth               ElementsAre("for (int &e : x)\n    e = 10;"));
1364e9192f83SShuai Wang 
1365b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef int& IntRef;"
1366e9192f83SShuai Wang                          "void f() { int x[2]; for (IntRef e : x) e = 10; }");
1367e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1368e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
1369e517e5cfSJonas Toth               ElementsAre("for (IntRef e : x)\n    e = 10;"));
1370e9192f83SShuai Wang }
1371e9192f83SShuai Wang 
1372e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModifiedByImplicitInit) {
1373e9192f83SShuai Wang   const auto AST =
1374b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }");
1375e9192f83SShuai Wang   const auto Results =
1376e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1377e517e5cfSJonas Toth   EXPECT_TRUE(isMutated(Results, AST.get()));
1378e9192f83SShuai Wang }
1379e9192f83SShuai Wang 
1380e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) {
1381b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }");
1382e9192f83SShuai Wang   auto Results =
1383e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1384e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1385e9192f83SShuai Wang 
1386b81bcb3aSShuai Wang   AST =
1387b81bcb3aSShuai Wang       buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }");
1388e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
138946ae26e7SJonas Toth   EXPECT_TRUE(isMutated(Results, AST.get()));
1390e9192f83SShuai Wang 
1391b81bcb3aSShuai Wang   AST = buildASTFromCode(
1392e9192f83SShuai Wang       "typedef int* IntPtr;"
1393e9192f83SShuai Wang       "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }");
1394e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
139546ae26e7SJonas Toth   EXPECT_TRUE(isMutated(Results, AST.get()));
1396e9192f83SShuai Wang }
1397e9192f83SShuai Wang 
1398e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) {
1399b81bcb3aSShuai Wang   auto AST =
1400b81bcb3aSShuai Wang       buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }");
1401e9192f83SShuai Wang   auto Results =
1402e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1403e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1404e9192f83SShuai Wang 
1405b81bcb3aSShuai Wang   AST = buildASTFromCode("typedef const int& CIntRef;"
1406e9192f83SShuai Wang                          "void f() { int x[2]; for (CIntRef e : x) e; }");
1407e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1408e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1409e9192f83SShuai Wang }
1410e9192f83SShuai Wang 
1411e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) {
1412e9192f83SShuai Wang   const auto AST =
1413b81bcb3aSShuai Wang       buildASTFromCode("struct V { int* begin(); int* end(); };"
1414e9192f83SShuai Wang                        "void f() { V x; for (int& e : x) e = 10; }");
1415e9192f83SShuai Wang   const auto Results =
1416e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1417e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()),
1418e517e5cfSJonas Toth               ElementsAre("for (int &e : x)\n    e = 10;"));
1419e9192f83SShuai Wang }
1420e9192f83SShuai Wang 
1421e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) {
1422b81bcb3aSShuai Wang   const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };"
1423e9192f83SShuai Wang                                     "void f() { V x; for (int& e : x) e; }");
1424e9192f83SShuai Wang   const auto Results =
1425e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1426e517e5cfSJonas Toth   EXPECT_TRUE(isMutated(Results, AST.get()));
1427e9192f83SShuai Wang }
1428e9192f83SShuai Wang 
1429e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) {
1430b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
1431e9192f83SShuai Wang       "struct V { const int* begin() const; const int* end() const; };"
1432e9192f83SShuai Wang       "void f() { V x; for (int e : x) e; }");
1433e9192f83SShuai Wang   const auto Results =
1434e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1435e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1436e9192f83SShuai Wang }
1437e9192f83SShuai Wang 
1438e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) {
1439b81bcb3aSShuai Wang   const auto AST = buildASTFromCode(
1440e9192f83SShuai Wang       "struct V { const int* begin() const; const int* end() const; };"
1441e9192f83SShuai Wang       "void f() { V x; for (const int& e : x) e; }");
1442e9192f83SShuai Wang   const auto Results =
1443e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1444e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1445e9192f83SShuai Wang }
1446e9192f83SShuai Wang 
1447e517e5cfSJonas Toth // section: unevaluated expressions
1448e517e5cfSJonas Toth 
1449e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) {
1450b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }");
1451e9192f83SShuai Wang   auto Results =
1452e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1453e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1454e9192f83SShuai Wang 
1455b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }");
1456e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1457e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1458e9192f83SShuai Wang 
1459b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }");
1460e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1461e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1462e9192f83SShuai Wang 
1463b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }");
1464e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1465e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1466e9192f83SShuai Wang 
1467b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { int x; alignof(x = 10); }");
1468e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1469e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1470e9192f83SShuai Wang 
1471b81bcb3aSShuai Wang   AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }");
1472e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1473e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1474e9192f83SShuai Wang 
1475b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs("namespace std { class type_info; }"
1476e9192f83SShuai Wang                                  "void f() { int x; typeid(x = 10); }",
1477e9192f83SShuai Wang                                  {"-frtti"});
1478e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1479e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1480e9192f83SShuai Wang 
1481b81bcb3aSShuai Wang   AST = buildASTFromCode(
1482e9192f83SShuai Wang       "void f() { int x; _Generic(x = 10, int: 0, default: 1); }");
1483e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1484e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1485e9192f83SShuai Wang }
1486e9192f83SShuai Wang 
1487e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) {
1488b81bcb3aSShuai Wang   auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }");
1489e9192f83SShuai Wang   auto Results =
1490e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1491e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++"));
1492e9192f83SShuai Wang 
1493b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
1494e9192f83SShuai Wang       "namespace std { class type_info; }"
1495e9192f83SShuai Wang       "struct A { virtual ~A(); }; struct B : A {};"
1496e9192f83SShuai Wang       "struct X { A& f(); }; void f() { X x; typeid(x.f()); }",
1497e9192f83SShuai Wang       {"-frtti"});
1498e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1499e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()"));
1500e9192f83SShuai Wang }
1501e9192f83SShuai Wang 
1502e517e5cfSJonas Toth // section: special case: smartpointers
1503e517e5cfSJonas Toth 
1504e9192f83SShuai Wang TEST(ExprMutationAnalyzerTest, UniquePtr) {
1505e9192f83SShuai Wang   const std::string UniquePtrDef =
1506e9192f83SShuai Wang       "template <class T> struct UniquePtr {"
1507e9192f83SShuai Wang       "  UniquePtr();"
1508e9192f83SShuai Wang       "  UniquePtr(const UniquePtr&) = delete;"
1509e9192f83SShuai Wang       "  UniquePtr(UniquePtr&&);"
1510e9192f83SShuai Wang       "  UniquePtr& operator=(const UniquePtr&) = delete;"
1511e9192f83SShuai Wang       "  UniquePtr& operator=(UniquePtr&&);"
1512e9192f83SShuai Wang       "  T& operator*() const;"
1513e9192f83SShuai Wang       "  T* operator->() const;"
1514e9192f83SShuai Wang       "};";
1515e9192f83SShuai Wang 
1516b81bcb3aSShuai Wang   auto AST = buildASTFromCode(UniquePtrDef +
1517b81bcb3aSShuai Wang                               "void f() { UniquePtr<int> x; *x = 10; }");
1518e9192f83SShuai Wang   auto Results =
1519e9192f83SShuai Wang       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1520e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10"));
1521e9192f83SShuai Wang 
1522b81bcb3aSShuai Wang   AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr<int> x; *x; }");
1523e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1524e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1525e9192f83SShuai Wang 
1526b81bcb3aSShuai Wang   AST = buildASTFromCode(UniquePtrDef +
1527e9192f83SShuai Wang                          "void f() { UniquePtr<const int> x; *x; }");
1528e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1529e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1530e9192f83SShuai Wang 
1531b81bcb3aSShuai Wang   AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };"
1532e9192f83SShuai Wang                                         "void f() { UniquePtr<S> x; x->v; }");
1533e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1534e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
1535e9192f83SShuai Wang 
1536b81bcb3aSShuai Wang   AST = buildASTFromCode(UniquePtrDef +
1537e9192f83SShuai Wang                          "struct S { int v; };"
1538e9192f83SShuai Wang                          "void f() { UniquePtr<const S> x; x->v; }");
1539e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1540e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1541e9192f83SShuai Wang 
1542b81bcb3aSShuai Wang   AST =
1543b81bcb3aSShuai Wang       buildASTFromCode(UniquePtrDef + "struct S { void mf(); };"
1544e9192f83SShuai Wang                                       "void f() { UniquePtr<S> x; x->mf(); }");
1545e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1546e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
1547e9192f83SShuai Wang 
1548b81bcb3aSShuai Wang   AST = buildASTFromCode(UniquePtrDef +
1549b81bcb3aSShuai Wang                          "struct S { void mf() const; };"
1550e9192f83SShuai Wang                          "void f() { UniquePtr<const S> x; x->mf(); }");
1551e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1552e9192f83SShuai Wang   EXPECT_FALSE(isMutated(Results, AST.get()));
1553e9192f83SShuai Wang 
1554b81bcb3aSShuai Wang   AST = buildASTFromCodeWithArgs(
1555e9192f83SShuai Wang       UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }",
1556e9192f83SShuai Wang       {"-fno-delayed-template-parsing"});
1557e9192f83SShuai Wang   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1558e9192f83SShuai Wang   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()"));
1559e9192f83SShuai Wang }
1560e9192f83SShuai Wang 
1561e517e5cfSJonas Toth // section: complex problems detected on real code
1562e517e5cfSJonas Toth 
15636e31714dSCongcong Cai TEST(ExprMutationAnalyzerTest, SelfRef) {
15646e31714dSCongcong Cai   std::unique_ptr<ASTUnit> AST{};
15656e31714dSCongcong Cai   SmallVector<BoundNodes, 1> Results{};
15666e31714dSCongcong Cai 
15676e31714dSCongcong Cai   AST = buildASTFromCodeWithArgs("void f() { int &x = x; }",
15686e31714dSCongcong Cai                                  {"-Wno-unused-value", "-Wno-uninitialized"});
15696e31714dSCongcong Cai   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
15706e31714dSCongcong Cai   EXPECT_FALSE(isDeclMutated(Results, AST.get()));
15716e31714dSCongcong Cai 
15726e31714dSCongcong Cai   AST = buildASTFromCodeWithArgs("void f() { int &x = x; x = 1; }",
15736e31714dSCongcong Cai                                  {"-Wno-unused-value", "-Wno-uninitialized"});
15746e31714dSCongcong Cai   Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
15756e31714dSCongcong Cai   EXPECT_TRUE(isDeclMutated(Results, AST.get()));
15766e31714dSCongcong Cai }
15776e31714dSCongcong Cai 
1578e517e5cfSJonas Toth TEST(ExprMutationAnalyzerTest, UnevaluatedContext) {
1579e517e5cfSJonas Toth   const std::string Example =
1580e517e5cfSJonas Toth       "template <typename T>"
1581e517e5cfSJonas Toth       "struct to_construct : T { to_construct(int &j) {} };"
1582e517e5cfSJonas Toth       "template <typename T>"
1583e517e5cfSJonas Toth       "void placement_new_in_unique_ptr() { int x = 0;"
1584e517e5cfSJonas Toth       "  new to_construct<T>(x);"
1585e517e5cfSJonas Toth       "}";
1586e517e5cfSJonas Toth   auto AST =
1587e517e5cfSJonas Toth       buildASTFromCodeWithArgs(Example, {"-fno-delayed-template-parsing"});
1588e517e5cfSJonas Toth   auto Results =
1589e517e5cfSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1590e517e5cfSJonas Toth   EXPECT_TRUE(isMutated(Results, AST.get()));
1591e517e5cfSJonas Toth   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(x)"));
1592e517e5cfSJonas Toth }
1593e517e5cfSJonas Toth 
159467b7e23fSJonas Toth TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) {
159567b7e23fSJonas Toth   const std::string Reproducer =
159667b7e23fSJonas Toth       "namespace std {"
159772315d02SRichard Smith       "template <class T> T &forward(T &A) { return static_cast<T&&>(A); }"
159867b7e23fSJonas Toth       "template <class T> struct __bind {"
159967b7e23fSJonas Toth       "  T f;"
160067b7e23fSJonas Toth       "  template <class V> __bind(T v, V &&) : f(forward(v)) {}"
160167b7e23fSJonas Toth       "};"
160267b7e23fSJonas Toth       "}"
160367b7e23fSJonas Toth       "void f() {"
160467b7e23fSJonas Toth       "  int x = 42;"
160567b7e23fSJonas Toth       "  auto Lambda = [] {};"
160667b7e23fSJonas Toth       "  std::__bind<decltype(Lambda)>(Lambda, x);"
160767b7e23fSJonas Toth       "}";
160867b7e23fSJonas Toth   auto AST11 = buildASTFromCodeWithArgs(Reproducer, {"-std=c++11"});
160967b7e23fSJonas Toth   auto Results11 =
161067b7e23fSJonas Toth       match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext());
161167b7e23fSJonas Toth   EXPECT_FALSE(isMutated(Results11, AST11.get()));
161267b7e23fSJonas Toth }
1613*53ea5ffcSCongcong Cai 
1614*53ea5ffcSCongcong Cai static bool isPointeeMutated(const SmallVectorImpl<BoundNodes> &Results,
1615*53ea5ffcSCongcong Cai                              ASTUnit *AST) {
1616*53ea5ffcSCongcong Cai   const auto *const S = selectFirst<Stmt>("stmt", Results);
1617*53ea5ffcSCongcong Cai   const auto *const E = selectFirst<Expr>("expr", Results);
1618*53ea5ffcSCongcong Cai   assert(S && E);
1619*53ea5ffcSCongcong Cai   TraversalKindScope RAII(AST->getASTContext(), TK_AsIs);
1620*53ea5ffcSCongcong Cai   return ExprMutationAnalyzer(*S, AST->getASTContext()).isPointeeMutated(E);
1621*53ea5ffcSCongcong Cai }
1622*53ea5ffcSCongcong Cai 
1623*53ea5ffcSCongcong Cai static bool isDeclPointeeMutated(const SmallVectorImpl<BoundNodes> &Results,
1624*53ea5ffcSCongcong Cai                                  ASTUnit *AST) {
1625*53ea5ffcSCongcong Cai   const auto *const S = selectFirst<Stmt>("stmt", Results);
1626*53ea5ffcSCongcong Cai   const auto *const D = selectFirst<Decl>("decl", Results);
1627*53ea5ffcSCongcong Cai   assert(S && D);
1628*53ea5ffcSCongcong Cai   TraversalKindScope RAII(AST->getASTContext(), TK_AsIs);
1629*53ea5ffcSCongcong Cai   return ExprMutationAnalyzer(*S, AST->getASTContext()).isPointeeMutated(D);
1630*53ea5ffcSCongcong Cai }
1631*53ea5ffcSCongcong Cai 
1632*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssign) {
1633*53ea5ffcSCongcong Cai   {
1634*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; int b = *x; }";
1635*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1636*53ea5ffcSCongcong Cai     auto Results =
1637*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1638*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1639*53ea5ffcSCongcong Cai   }
1640*53ea5ffcSCongcong Cai   {
1641*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; *x = 100; }";
1642*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1643*53ea5ffcSCongcong Cai     auto Results =
1644*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1645*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1646*53ea5ffcSCongcong Cai   }
1647*53ea5ffcSCongcong Cai   {
1648*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; (*x)++; }";
1649*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"});
1650*53ea5ffcSCongcong Cai     auto Results =
1651*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1652*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1653*53ea5ffcSCongcong Cai   }
1654*53ea5ffcSCongcong Cai }
1655*53ea5ffcSCongcong Cai 
1656*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByMember) {
1657*53ea5ffcSCongcong Cai   {
1658*53ea5ffcSCongcong Cai     const std::string Code =
1659*53ea5ffcSCongcong Cai         "struct A { int v; }; void f() { A* x = nullptr; int b = x->v; }";
1660*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1661*53ea5ffcSCongcong Cai     auto Results =
1662*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1663*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1664*53ea5ffcSCongcong Cai   }
1665*53ea5ffcSCongcong Cai   {
1666*53ea5ffcSCongcong Cai     const std::string Code =
1667*53ea5ffcSCongcong Cai         "struct A { int v; }; void f() { A* x = nullptr; x->v = 1; }";
1668*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1669*53ea5ffcSCongcong Cai     auto Results =
1670*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1671*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1672*53ea5ffcSCongcong Cai   }
1673*53ea5ffcSCongcong Cai   {
1674*53ea5ffcSCongcong Cai     const std::string Code =
1675*53ea5ffcSCongcong Cai         "struct A { int v; }; void f() { A* x = nullptr; x->v++; }";
1676*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"});
1677*53ea5ffcSCongcong Cai     auto Results =
1678*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1679*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1680*53ea5ffcSCongcong Cai   }
1681*53ea5ffcSCongcong Cai }
1682*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByMethod) {
1683*53ea5ffcSCongcong Cai   {
1684*53ea5ffcSCongcong Cai     const std::string Code = "struct A { int v; void foo(); };"
1685*53ea5ffcSCongcong Cai                              "void f() { A* x = nullptr; x->foo(); }";
1686*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1687*53ea5ffcSCongcong Cai     auto Results =
1688*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1689*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1690*53ea5ffcSCongcong Cai   }
1691*53ea5ffcSCongcong Cai   {
1692*53ea5ffcSCongcong Cai     const std::string Code = "struct A { int v; void foo() const; };"
1693*53ea5ffcSCongcong Cai                              "void f() { A* x = nullptr; x->foo(); }";
1694*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1695*53ea5ffcSCongcong Cai     auto Results =
1696*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1697*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1698*53ea5ffcSCongcong Cai   }
1699*53ea5ffcSCongcong Cai }
1700*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByOperatorOverload) {
1701*53ea5ffcSCongcong Cai   {
1702*53ea5ffcSCongcong Cai     const std::string Code = "struct A { int v; int operator++(); };"
1703*53ea5ffcSCongcong Cai                              "void f() { A* x = nullptr; x->operator++(); }";
1704*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1705*53ea5ffcSCongcong Cai     auto Results =
1706*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1707*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1708*53ea5ffcSCongcong Cai   }
1709*53ea5ffcSCongcong Cai   {
1710*53ea5ffcSCongcong Cai     const std::string Code = "struct A { int v; int operator++() const; };"
1711*53ea5ffcSCongcong Cai                              "void f() { A* x = nullptr; x->operator++(); }";
1712*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1713*53ea5ffcSCongcong Cai     auto Results =
1714*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1715*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1716*53ea5ffcSCongcong Cai   }
1717*53ea5ffcSCongcong Cai }
1718*53ea5ffcSCongcong Cai 
1719*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByInitToNonConst) {
1720*53ea5ffcSCongcong Cai   {
1721*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; int const* b = x; }";
1722*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1723*53ea5ffcSCongcong Cai     auto Results =
1724*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1725*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1726*53ea5ffcSCongcong Cai   }
1727*53ea5ffcSCongcong Cai   {
1728*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; int* b = x; }";
1729*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1730*53ea5ffcSCongcong Cai     auto Results =
1731*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1732*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1733*53ea5ffcSCongcong Cai   }
1734*53ea5ffcSCongcong Cai   {
1735*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; int* const b = x; }";
1736*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1737*53ea5ffcSCongcong Cai     auto Results =
1738*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1739*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1740*53ea5ffcSCongcong Cai   }
1741*53ea5ffcSCongcong Cai }
1742*53ea5ffcSCongcong Cai 
1743*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssignToNonConst) {
1744*53ea5ffcSCongcong Cai   {
1745*53ea5ffcSCongcong Cai     const std::string Code =
1746*53ea5ffcSCongcong Cai         "void f() { int* x = nullptr; int const* b; b = x; }";
1747*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1748*53ea5ffcSCongcong Cai     auto Results =
1749*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1750*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1751*53ea5ffcSCongcong Cai   }
1752*53ea5ffcSCongcong Cai   {
1753*53ea5ffcSCongcong Cai     const std::string Code = "void f() { int* x = nullptr; int* b; b = x; }";
1754*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1755*53ea5ffcSCongcong Cai     auto Results =
1756*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1757*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1758*53ea5ffcSCongcong Cai   }
1759*53ea5ffcSCongcong Cai }
1760*53ea5ffcSCongcong Cai 
1761*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgument) {
1762*53ea5ffcSCongcong Cai   {
1763*53ea5ffcSCongcong Cai     const std::string Code =
1764*53ea5ffcSCongcong Cai         "void b(int const*); void f() { int* x = nullptr; b(x); }";
1765*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1766*53ea5ffcSCongcong Cai     auto Results =
1767*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1768*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1769*53ea5ffcSCongcong Cai   }
1770*53ea5ffcSCongcong Cai   {
1771*53ea5ffcSCongcong Cai     const std::string Code =
1772*53ea5ffcSCongcong Cai         "void b(int *); void f() { int* x = nullptr; b(x); }";
1773*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1774*53ea5ffcSCongcong Cai     auto Results =
1775*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1776*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1777*53ea5ffcSCongcong Cai   }
1778*53ea5ffcSCongcong Cai }
1779*53ea5ffcSCongcong Cai 
1780*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgumentInConstruct) {
1781*53ea5ffcSCongcong Cai   {
1782*53ea5ffcSCongcong Cai     const std::string Code = "struct A { A(int const*); };"
1783*53ea5ffcSCongcong Cai                              "void f() { int *x; A a{x}; }";
1784*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1785*53ea5ffcSCongcong Cai     auto Results =
1786*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1787*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1788*53ea5ffcSCongcong Cai   }
1789*53ea5ffcSCongcong Cai   {
1790*53ea5ffcSCongcong Cai     const std::string Code = "struct A { A(int const*); };"
1791*53ea5ffcSCongcong Cai                              "void f() { int *x; A a(x); }";
1792*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1793*53ea5ffcSCongcong Cai     auto Results =
1794*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1795*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1796*53ea5ffcSCongcong Cai   }
1797*53ea5ffcSCongcong Cai   {
1798*53ea5ffcSCongcong Cai     const std::string Code = "struct A { A(int const*); };"
1799*53ea5ffcSCongcong Cai                              "void f() { int *x; A a = x; }";
1800*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1801*53ea5ffcSCongcong Cai     auto Results =
1802*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1803*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1804*53ea5ffcSCongcong Cai   }
1805*53ea5ffcSCongcong Cai   {
1806*53ea5ffcSCongcong Cai     const std::string Code = "struct A { A(int *); };"
1807*53ea5ffcSCongcong Cai                              "void f() { int *x; A a{x}; }";
1808*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1809*53ea5ffcSCongcong Cai     auto Results =
1810*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1811*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1812*53ea5ffcSCongcong Cai   }
1813*53ea5ffcSCongcong Cai }
1814*53ea5ffcSCongcong Cai 
1815*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest,
1816*53ea5ffcSCongcong Cai      PointeeMutatedByPassAsArgumentInTemplateConstruct) {
1817*53ea5ffcSCongcong Cai   const std::string Code = "template<class T> void f() { int *x; new T(x); }";
1818*53ea5ffcSCongcong Cai   auto AST = buildASTFromCodeWithArgs(Code, {"-fno-delayed-template-parsing"});
1819*53ea5ffcSCongcong Cai   auto Results =
1820*53ea5ffcSCongcong Cai       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1821*53ea5ffcSCongcong Cai   EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1822*53ea5ffcSCongcong Cai }
1823*53ea5ffcSCongcong Cai 
1824*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgumentInInitList) {
1825*53ea5ffcSCongcong Cai   {
1826*53ea5ffcSCongcong Cai     const std::string Code =
1827*53ea5ffcSCongcong Cai         "namespace std {"
1828*53ea5ffcSCongcong Cai         "template<class T>"
1829*53ea5ffcSCongcong Cai         "struct initializer_list{ T const* begin; T const* end; };"
1830*53ea5ffcSCongcong Cai         "}"
1831*53ea5ffcSCongcong Cai         "void f() { int *x; std::initializer_list<int*> a{x, x, x}; }";
1832*53ea5ffcSCongcong Cai     auto AST =
1833*53ea5ffcSCongcong Cai         buildASTFromCodeWithArgs(Code, {"-fno-delayed-template-parsing"});
1834*53ea5ffcSCongcong Cai     auto Results =
1835*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1836*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1837*53ea5ffcSCongcong Cai   }
1838*53ea5ffcSCongcong Cai }
1839*53ea5ffcSCongcong Cai 
1840*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByThis) {
1841*53ea5ffcSCongcong Cai   {
1842*53ea5ffcSCongcong Cai     const std::string Code =
1843*53ea5ffcSCongcong Cai         "struct A { void m() const; }; void f() { A* x = nullptr; x->m(); }";
1844*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1845*53ea5ffcSCongcong Cai     auto Results =
1846*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1847*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1848*53ea5ffcSCongcong Cai   }
1849*53ea5ffcSCongcong Cai   {
1850*53ea5ffcSCongcong Cai     const std::string Code =
1851*53ea5ffcSCongcong Cai         "struct A { void m(); }; void f() { A* x = nullptr; x->m(); }";
1852*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {});
1853*53ea5ffcSCongcong Cai     auto Results =
1854*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1855*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1856*53ea5ffcSCongcong Cai   }
1857*53ea5ffcSCongcong Cai }
1858*53ea5ffcSCongcong Cai 
1859*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByExplicitCastToNonConst) {
1860*53ea5ffcSCongcong Cai   {
1861*53ea5ffcSCongcong Cai     const std::string Code =
1862*53ea5ffcSCongcong Cai         "void f() { int* x = nullptr; static_cast<int const*>(x); }";
1863*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1864*53ea5ffcSCongcong Cai     auto Results =
1865*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1866*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1867*53ea5ffcSCongcong Cai   }
1868*53ea5ffcSCongcong Cai   {
1869*53ea5ffcSCongcong Cai     const std::string Code =
1870*53ea5ffcSCongcong Cai         "void f() { int* x = nullptr; static_cast<int*>(x); }";
1871*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1872*53ea5ffcSCongcong Cai     auto Results =
1873*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1874*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1875*53ea5ffcSCongcong Cai   }
1876*53ea5ffcSCongcong Cai }
1877*53ea5ffcSCongcong Cai 
1878*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByConstCastToNonConst) {
1879*53ea5ffcSCongcong Cai   // const_cast to non-const even treat as mutated.
1880*53ea5ffcSCongcong Cai   {
1881*53ea5ffcSCongcong Cai     const std::string Code =
1882*53ea5ffcSCongcong Cai         "void f() { int* x = nullptr; const_cast<int const*>(x); }";
1883*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1884*53ea5ffcSCongcong Cai     auto Results =
1885*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1886*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1887*53ea5ffcSCongcong Cai   }
1888*53ea5ffcSCongcong Cai   {
1889*53ea5ffcSCongcong Cai     const std::string Code =
1890*53ea5ffcSCongcong Cai         "void f() { int* x = nullptr; const_cast<int*>(x); }";
1891*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1892*53ea5ffcSCongcong Cai     auto Results =
1893*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1894*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1895*53ea5ffcSCongcong Cai   }
1896*53ea5ffcSCongcong Cai }
1897*53ea5ffcSCongcong Cai 
1898*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByUnresolvedCall) {
1899*53ea5ffcSCongcong Cai   const std::string Code =
1900*53ea5ffcSCongcong Cai       "template <class T> struct S;"
1901*53ea5ffcSCongcong Cai       "template <class T> void f() { S<T> s; int* x = nullptr; s.m(x); }";
1902*53ea5ffcSCongcong Cai   auto AST = buildASTFromCodeWithArgs(
1903*53ea5ffcSCongcong Cai       Code, {"-fno-delayed-template-parsing", "-Wno-everything"});
1904*53ea5ffcSCongcong Cai   auto Results =
1905*53ea5ffcSCongcong Cai       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1906*53ea5ffcSCongcong Cai   EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1907*53ea5ffcSCongcong Cai }
1908*53ea5ffcSCongcong Cai 
1909*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssignToUnknownType) {
1910*53ea5ffcSCongcong Cai   {
1911*53ea5ffcSCongcong Cai     const std::string Code = "template <class T> void f() {"
1912*53ea5ffcSCongcong Cai                              "  int* x = nullptr;"
1913*53ea5ffcSCongcong Cai                              "  T t = x;"
1914*53ea5ffcSCongcong Cai                              "}";
1915*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(
1916*53ea5ffcSCongcong Cai         Code, {"-fno-delayed-template-parsing", "-Wno-everything"});
1917*53ea5ffcSCongcong Cai     auto Results =
1918*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1919*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1920*53ea5ffcSCongcong Cai   }
1921*53ea5ffcSCongcong Cai   {
1922*53ea5ffcSCongcong Cai     const std::string Code = "template <class T> void f() {"
1923*53ea5ffcSCongcong Cai                              "  int* x = nullptr;"
1924*53ea5ffcSCongcong Cai                              "  typename T::t t = x;"
1925*53ea5ffcSCongcong Cai                              "}";
1926*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(
1927*53ea5ffcSCongcong Cai         Code, {"-fno-delayed-template-parsing", "-Wno-everything"});
1928*53ea5ffcSCongcong Cai     auto Results =
1929*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1930*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1931*53ea5ffcSCongcong Cai   }
1932*53ea5ffcSCongcong Cai }
1933*53ea5ffcSCongcong Cai 
1934*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByLambdaCapture) {
1935*53ea5ffcSCongcong Cai   const std::string Code = R"(
1936*53ea5ffcSCongcong Cai       void f() {
1937*53ea5ffcSCongcong Cai         int* x;
1938*53ea5ffcSCongcong Cai         [x] () { *x = 1; };
1939*53ea5ffcSCongcong Cai       })";
1940*53ea5ffcSCongcong Cai   auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1941*53ea5ffcSCongcong Cai   auto Results =
1942*53ea5ffcSCongcong Cai       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1943*53ea5ffcSCongcong Cai   EXPECT_TRUE(isDeclPointeeMutated(Results, AST.get()));
1944*53ea5ffcSCongcong Cai }
1945*53ea5ffcSCongcong Cai 
1946*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByLambdaCaptureInit) {
1947*53ea5ffcSCongcong Cai   const std::string Code = R"(
1948*53ea5ffcSCongcong Cai       void f() {
1949*53ea5ffcSCongcong Cai         int* x;
1950*53ea5ffcSCongcong Cai         [t = x] () { *t = 1; };
1951*53ea5ffcSCongcong Cai       })";
1952*53ea5ffcSCongcong Cai   auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1953*53ea5ffcSCongcong Cai   auto Results =
1954*53ea5ffcSCongcong Cai       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1955*53ea5ffcSCongcong Cai   EXPECT_TRUE(isDeclPointeeMutated(Results, AST.get()));
1956*53ea5ffcSCongcong Cai }
1957*53ea5ffcSCongcong Cai 
1958*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByPointerArithmeticAdd) {
1959*53ea5ffcSCongcong Cai   {
1960*53ea5ffcSCongcong Cai     const std::string Code = R"(
1961*53ea5ffcSCongcong Cai       void f() {
1962*53ea5ffcSCongcong Cai         int* x;
1963*53ea5ffcSCongcong Cai         int* y = x + 1;
1964*53ea5ffcSCongcong Cai       })";
1965*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1966*53ea5ffcSCongcong Cai     auto Results =
1967*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1968*53ea5ffcSCongcong Cai     EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1969*53ea5ffcSCongcong Cai   }
1970*53ea5ffcSCongcong Cai   {
1971*53ea5ffcSCongcong Cai     const std::string Code = R"(
1972*53ea5ffcSCongcong Cai       void f() {
1973*53ea5ffcSCongcong Cai         int* x;
1974*53ea5ffcSCongcong Cai         x + 1;
1975*53ea5ffcSCongcong Cai       })";
1976*53ea5ffcSCongcong Cai     auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1977*53ea5ffcSCongcong Cai     auto Results =
1978*53ea5ffcSCongcong Cai         match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1979*53ea5ffcSCongcong Cai     EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
1980*53ea5ffcSCongcong Cai   }
1981*53ea5ffcSCongcong Cai }
1982*53ea5ffcSCongcong Cai 
1983*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByPointerArithmeticSubElement) {
1984*53ea5ffcSCongcong Cai   const std::string Code = R"(
1985*53ea5ffcSCongcong Cai       void f() {
1986*53ea5ffcSCongcong Cai         int* x;
1987*53ea5ffcSCongcong Cai         int* y = &x[1];
1988*53ea5ffcSCongcong Cai       })";
1989*53ea5ffcSCongcong Cai   auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
1990*53ea5ffcSCongcong Cai   auto Results =
1991*53ea5ffcSCongcong Cai       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
1992*53ea5ffcSCongcong Cai   EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
1993*53ea5ffcSCongcong Cai }
1994*53ea5ffcSCongcong Cai 
1995*53ea5ffcSCongcong Cai TEST(ExprMutationAnalyzerTest, PointeeMutatedByConditionOperator) {
1996*53ea5ffcSCongcong Cai   const std::string Code = R"(
1997*53ea5ffcSCongcong Cai       void f() {
1998*53ea5ffcSCongcong Cai         int* x;
1999*53ea5ffcSCongcong Cai         int* y = 1 ? nullptr : x;
2000*53ea5ffcSCongcong Cai       })";
2001*53ea5ffcSCongcong Cai   auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
2002*53ea5ffcSCongcong Cai   auto Results =
2003*53ea5ffcSCongcong Cai       match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
2004*53ea5ffcSCongcong Cai   EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
2005*53ea5ffcSCongcong Cai }
2006*53ea5ffcSCongcong Cai 
2007e9192f83SShuai Wang } // namespace clang
2008