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