1 //===---------- ExprMutationAnalyzerTest.cpp ------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" 10 #include "clang/AST/TypeLoc.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/ASTMatchers/ASTMatchers.h" 13 #include "clang/Tooling/Tooling.h" 14 #include "llvm/ADT/SmallString.h" 15 #include "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 #include <cctype> 18 19 namespace clang { 20 21 using namespace clang::ast_matchers; 22 using ::testing::ElementsAre; 23 using ::testing::ResultOf; 24 using ::testing::Values; 25 26 namespace { 27 28 using ExprMatcher = internal::Matcher<Expr>; 29 using StmtMatcher = internal::Matcher<Stmt>; 30 31 std::unique_ptr<ASTUnit> 32 buildASTFromCodeWithArgs(const Twine &Code, 33 const std::vector<std::string> &Args) { 34 SmallString<1024> CodeStorage; 35 auto AST = 36 tooling::buildASTFromCodeWithArgs(Code.toStringRef(CodeStorage), Args); 37 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred()); 38 return AST; 39 } 40 41 std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code) { 42 return buildASTFromCodeWithArgs(Code, {}); 43 } 44 45 ExprMatcher declRefTo(StringRef Name) { 46 return declRefExpr(to(namedDecl(hasName(Name)))); 47 } 48 49 StmtMatcher withEnclosingCompound(ExprMatcher Matcher) { 50 return expr(Matcher, hasAncestor(compoundStmt().bind("stmt"))).bind("expr"); 51 } 52 53 bool isMutated(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) { 54 const auto *const S = selectFirst<Stmt>("stmt", Results); 55 const auto *const E = selectFirst<Expr>("expr", Results); 56 TraversalKindScope RAII(AST->getASTContext(), TK_AsIs); 57 return ExprMutationAnalyzer(*S, AST->getASTContext()).isMutated(E); 58 } 59 60 SmallVector<std::string, 1> 61 mutatedBy(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) { 62 const auto *const S = selectFirst<Stmt>("stmt", Results); 63 SmallVector<std::string, 1> Chain; 64 ExprMutationAnalyzer Analyzer(*S, AST->getASTContext()); 65 66 for (const auto *E = selectFirst<Expr>("expr", Results); E != nullptr;) { 67 const Stmt *By = Analyzer.findMutation(E); 68 if (!By) 69 break; 70 71 std::string Buffer; 72 llvm::raw_string_ostream Stream(Buffer); 73 By->printPretty(Stream, nullptr, AST->getASTContext().getPrintingPolicy()); 74 Chain.emplace_back(StringRef(Stream.str()).trim().str()); 75 E = dyn_cast<DeclRefExpr>(By); 76 } 77 return Chain; 78 } 79 80 std::string removeSpace(std::string s) { 81 s.erase(std::remove_if(s.begin(), s.end(), 82 [](char c) { return llvm::isSpace(c); }), 83 s.end()); 84 return s; 85 } 86 87 const std::string StdRemoveReference = 88 "namespace std {" 89 "template<class T> struct remove_reference { typedef T type; };" 90 "template<class T> struct remove_reference<T&> { typedef T type; };" 91 "template<class T> struct remove_reference<T&&> { typedef T type; }; }"; 92 93 const std::string StdMove = 94 "namespace std {" 95 "template<class T> typename remove_reference<T>::type&& " 96 "move(T&& t) noexcept {" 97 "return static_cast<typename remove_reference<T>::type&&>(t); } }"; 98 99 const std::string StdForward = 100 "namespace std {" 101 "template<class T> T&& " 102 "forward(typename remove_reference<T>::type& t) noexcept { return t; }" 103 "template<class T> T&& " 104 "forward(typename remove_reference<T>::type&& t) noexcept { return t; } }"; 105 106 } // namespace 107 108 TEST(ExprMutationAnalyzerTest, Trivial) { 109 const auto AST = buildASTFromCode("void f() { int x; x; }"); 110 const auto Results = 111 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 112 EXPECT_FALSE(isMutated(Results, AST.get())); 113 } 114 115 class AssignmentTest : public ::testing::TestWithParam<std::string> {}; 116 117 // This test is for the most basic and direct modification of a variable, 118 // assignment to it (e.g. `x = 10;`). 119 // It additionally tests that references to a variable are not only captured 120 // directly but expressions that result in the variable are handled, too. 121 // This includes the comma operator, parens and the ternary operator. 122 TEST_P(AssignmentTest, AssignmentModifies) { 123 // Test the detection of the raw expression modifications. 124 { 125 const std::string ModExpr = "x " + GetParam() + " 10"; 126 const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); 127 const auto Results = 128 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 129 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 130 } 131 132 // Test the detection if the expression is surrounded by parens. 133 { 134 const std::string ModExpr = "(x) " + GetParam() + " 10"; 135 const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); 136 const auto Results = 137 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 138 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 139 } 140 141 // Test the detection if the comma operator yields the expression as result. 142 { 143 const std::string ModExpr = "x " + GetParam() + " 10"; 144 const auto AST = buildASTFromCodeWithArgs( 145 "void f() { int x, y; y, " + ModExpr + "; }", {"-Wno-unused-value"}); 146 const auto Results = 147 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 148 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 149 } 150 151 // Ensure no detection if the comma operator does not yield the expression as 152 // result. 153 { 154 const std::string ModExpr = "y, x, y " + GetParam() + " 10"; 155 const auto AST = buildASTFromCodeWithArgs( 156 "void f() { int x, y; " + ModExpr + "; }", {"-Wno-unused-value"}); 157 const auto Results = 158 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 159 EXPECT_FALSE(isMutated(Results, AST.get())); 160 } 161 162 // Test the detection if the a ternary operator can result in the expression. 163 { 164 const std::string ModExpr = "(y != 0 ? y : x) " + GetParam() + " 10"; 165 const auto AST = 166 buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }"); 167 const auto Results = 168 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 169 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 170 } 171 172 // Test the detection if the a ternary operator can result in the expression 173 // through multiple nesting of ternary operators. 174 { 175 const std::string ModExpr = 176 "(y != 0 ? (y > 5 ? y : x) : (y)) " + GetParam() + " 10"; 177 const auto AST = 178 buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }"); 179 const auto Results = 180 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 181 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 182 } 183 184 // Test the detection if the a ternary operator can result in the expression 185 // with additional parens. 186 { 187 const std::string ModExpr = "(y != 0 ? (y) : ((x))) " + GetParam() + " 10"; 188 const auto AST = 189 buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }"); 190 const auto Results = 191 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 192 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 193 } 194 195 // Test the detection for the binary conditional operator. 196 { 197 const std::string ModExpr = "(y ?: x) " + GetParam() + " 10"; 198 const auto AST = 199 buildASTFromCode("void f() { int y = 0, x; " + ModExpr + "; }"); 200 const auto Results = 201 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 202 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 203 } 204 } 205 206 INSTANTIATE_TEST_SUITE_P(AllAssignmentOperators, AssignmentTest, 207 Values("=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", 208 "^=", "<<=", ">>=") ); 209 210 TEST(ExprMutationAnalyzerTest, AssignmentConditionalWithInheritance) { 211 const auto AST = buildASTFromCode("struct Base {void nonconst(); };" 212 "struct Derived : Base {};" 213 "static void f() {" 214 " Derived x, y;" 215 " Base &b = true ? x : y;" 216 " b.nonconst();" 217 "}"); 218 const auto Results = 219 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 220 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("b", "b.nonconst()")); 221 } 222 223 class IncDecTest : public ::testing::TestWithParam<std::string> {}; 224 225 TEST_P(IncDecTest, IncDecModifies) { 226 const std::string ModExpr = GetParam(); 227 const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); 228 const auto Results = 229 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 230 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 231 } 232 233 INSTANTIATE_TEST_SUITE_P(AllIncDecOperators, IncDecTest, 234 Values("++x", "--x", "x++", "x--", "++(x)", "--(x)", 235 "(x)++", "(x)--") ); 236 237 // Section: member functions 238 239 TEST(ExprMutationAnalyzerTest, NonConstMemberFunc) { 240 const auto AST = buildASTFromCode( 241 "void f() { struct Foo { void mf(); }; Foo x; x.mf(); }"); 242 const auto Results = 243 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 244 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); 245 } 246 247 TEST(ExprMutationAnalyzerTest, AssumedNonConstMemberFunc) { 248 auto AST = buildASTFromCodeWithArgs( 249 "struct X { template <class T> void mf(); };" 250 "template <class T> void f() { X x; x.mf<T>(); }", 251 {"-fno-delayed-template-parsing"}); 252 auto Results = 253 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 254 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf<T>()")); 255 256 AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.mf(); }", 257 {"-fno-delayed-template-parsing"}); 258 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 259 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); 260 261 AST = buildASTFromCodeWithArgs( 262 "template <class T> struct X;" 263 "template <class T> void f() { X<T> x; x.mf(); }", 264 {"-fno-delayed-template-parsing"}); 265 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 266 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); 267 } 268 269 TEST(ExprMutationAnalyzerTest, ConstMemberFunc) { 270 const auto AST = buildASTFromCode( 271 "void f() { struct Foo { void mf() const; }; Foo x; x.mf(); }"); 272 const auto Results = 273 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 274 EXPECT_FALSE(isMutated(Results, AST.get())); 275 } 276 277 TEST(ExprMutationAnalyzerTest, TypeDependentMemberCall) { 278 const auto AST = buildASTFromCodeWithArgs( 279 "template <class T> class vector { void push_back(T); }; " 280 "template <class T> void f() { vector<T> x; x.push_back(T()); }", 281 {"-fno-delayed-template-parsing"}); 282 const auto Results = 283 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 284 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.push_back(T())")); 285 } 286 287 TEST(ExprMutationAnalyzerTest, MemberPointerMemberCall) { 288 { 289 const auto AST = 290 buildASTFromCode("struct X {};" 291 "using T = int (X::*)();" 292 "void f(X &x, T m) { X &ref = x; (ref.*m)(); }"); 293 const auto Results = 294 match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext()); 295 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(ref .* m)()")); 296 } 297 { 298 const auto AST = 299 buildASTFromCode("struct X {};" 300 "using T = int (X::*)();" 301 "void f(X &x, T const m) { X &ref = x; (ref.*m)(); }"); 302 const auto Results = 303 match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext()); 304 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(ref .* m)()")); 305 } 306 { 307 const auto AST = 308 buildASTFromCode("struct X {};" 309 "using T = int (X::*)() const;" 310 "void f(X &x, T m) { X &ref = x; (ref.*m)(); }"); 311 const auto Results = 312 match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext()); 313 EXPECT_FALSE(isMutated(Results, AST.get())); 314 } 315 } 316 317 // Section: overloaded operators 318 319 TEST(ExprMutationAnalyzerTest, NonConstOperator) { 320 const auto AST = buildASTFromCode( 321 "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }"); 322 const auto Results = 323 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 324 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10")); 325 } 326 327 TEST(ExprMutationAnalyzerTest, ConstOperator) { 328 const auto AST = buildASTFromCode( 329 "void f() { struct Foo { int operator()() const; }; Foo x; x(); }"); 330 const auto Results = 331 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 332 EXPECT_FALSE(isMutated(Results, AST.get())); 333 } 334 335 TEST(ExprMutationAnalyzerTest, UnresolvedOperator) { 336 const auto AST = buildASTFromCodeWithArgs( 337 "template <typename Stream> void input_operator_template() {" 338 "Stream x; unsigned y = 42;" 339 "x >> y; }", 340 {"-fno-delayed-template-parsing"}); 341 const auto Results = 342 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 343 EXPECT_TRUE(isMutated(Results, AST.get())); 344 } 345 346 TEST(ExprMutationAnalyzerTest, DependentOperatorWithNonDependentOperand) { 347 // gh57297 348 // The expression to check may not be the dependent operand in a dependent 349 // operator. 350 351 // Explicitly not declaring a (templated) stream operator 352 // so the `<<` is a `binaryOperator` with a dependent type. 353 const auto AST = buildASTFromCodeWithArgs( 354 "struct Stream { };" 355 "template <typename T> void f() { T t; Stream x; x << t; }", 356 {"-fno-delayed-template-parsing"}); 357 const auto Results = 358 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 359 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x << t")); 360 } 361 362 // Section: expression as call argument 363 364 TEST(ExprMutationAnalyzerTest, ByValueArgument) { 365 auto AST = buildASTFromCode("void g(int); void f() { int x; g(x); }"); 366 auto Results = 367 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 368 EXPECT_FALSE(isMutated(Results, AST.get())); 369 370 AST = buildASTFromCode("void g(int*); void f() { int* x; g(x); }"); 371 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 372 EXPECT_FALSE(isMutated(Results, AST.get())); 373 374 AST = buildASTFromCode("typedef int* IntPtr;" 375 "void g(IntPtr); void f() { int* x; g(x); }"); 376 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 377 EXPECT_FALSE(isMutated(Results, AST.get())); 378 379 AST = buildASTFromCode( 380 "struct A {}; A operator+(A, int); void f() { A x; x + 1; }"); 381 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 382 EXPECT_FALSE(isMutated(Results, AST.get())); 383 384 AST = buildASTFromCode("void f() { struct A { A(int); }; int x; A y(x); }"); 385 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 386 EXPECT_FALSE(isMutated(Results, AST.get())); 387 388 AST = buildASTFromCode("struct A { A(); A& operator=(A); };" 389 "void f() { A x, y; y = x; }"); 390 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 391 EXPECT_FALSE(isMutated(Results, AST.get())); 392 393 AST = buildASTFromCode( 394 "template <int> struct A { A(); A(const A&); static void mf(A) {} };" 395 "void f() { A<0> x; A<0>::mf(x); }"); 396 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 397 EXPECT_FALSE(isMutated(Results, AST.get())); 398 } 399 400 TEST(ExprMutationAnalyzerTest, ByConstValueArgument) { 401 auto AST = buildASTFromCode("void g(const int); void f() { int x; g(x); }"); 402 auto Results = 403 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 404 EXPECT_FALSE(isMutated(Results, AST.get())); 405 406 AST = buildASTFromCode("void g(int* const); void f() { int* x; g(x); }"); 407 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 408 EXPECT_FALSE(isMutated(Results, AST.get())); 409 410 AST = buildASTFromCode("typedef int* const CIntPtr;" 411 "void g(CIntPtr); void f() { int* x; g(x); }"); 412 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 413 EXPECT_FALSE(isMutated(Results, AST.get())); 414 415 AST = buildASTFromCode( 416 "struct A {}; A operator+(const A, int); void f() { A x; x + 1; }"); 417 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 418 EXPECT_FALSE(isMutated(Results, AST.get())); 419 420 AST = buildASTFromCode( 421 "void f() { struct A { A(const int); }; int x; A y(x); }"); 422 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 423 EXPECT_FALSE(isMutated(Results, AST.get())); 424 425 AST = buildASTFromCode("template <int> struct A { A(); A(const A&);" 426 "static void mf(const A&) {} };" 427 "void f() { A<0> x; A<0>::mf(x); }"); 428 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 429 EXPECT_FALSE(isMutated(Results, AST.get())); 430 } 431 432 TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) { 433 auto AST = buildASTFromCode("void g(int&); void f() { int x; g(x); }"); 434 auto Results = 435 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 436 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 437 438 AST = buildASTFromCode("typedef int& IntRef;" 439 "void g(IntRef); void f() { int x; g(x); }"); 440 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 441 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 442 443 AST = buildASTFromCode("template <class T> using TRef = T&;" 444 "void g(TRef<int>); void f() { int x; g(x); }"); 445 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 446 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 447 448 AST = buildASTFromCode( 449 "template <class T> struct identity { using type = T; };" 450 "template <class T, class U = T&> void g(typename identity<U>::type);" 451 "void f() { int x; g<int>(x); }"); 452 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 453 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g<int>(x)")); 454 455 AST = buildASTFromCode("typedef int* IntPtr;" 456 "void g(IntPtr&); void f() { int* x; g(x); }"); 457 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 458 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 459 460 AST = buildASTFromCode("typedef int* IntPtr; typedef IntPtr& IntPtrRef;" 461 "void g(IntPtrRef); void f() { int* x; g(x); }"); 462 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 463 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 464 465 AST = buildASTFromCode( 466 "struct A {}; A operator+(A&, int); void f() { A x; x + 1; }"); 467 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 468 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1")); 469 470 AST = buildASTFromCode("void f() { struct A { A(int&); }; int x; A y(x); }"); 471 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 472 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 473 474 AST = buildASTFromCode("void f() { struct A { A(); A(A&); }; A x; A y(x); }"); 475 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 476 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 477 478 AST = buildASTFromCode( 479 "template <int> struct A { A(); A(const A&); static void mf(A&) {} };" 480 "void f() { A<0> x; A<0>::mf(x); }"); 481 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 482 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("A<0>::mf(x)")); 483 } 484 485 TEST(ExprMutationAnalyzerTest, ByNonConstRefArgumentFunctionTypeDependent) { 486 auto AST = buildASTFromCodeWithArgs( 487 "enum MyEnum { foo, bar };" 488 "void tryParser(unsigned& first, MyEnum Type) { first++, (void)Type; }" 489 "template <MyEnum Type> void parse() {" 490 " auto parser = [](unsigned& first) { first++; tryParser(first, Type); " 491 "};" 492 " unsigned x = 42;" 493 " parser(x);" 494 "}", 495 {"-fno-delayed-template-parsing"}); 496 auto Results = 497 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 498 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("parser(x)")); 499 } 500 501 TEST(ExprMutationAnalyzerTest, ByConstRefArgument) { 502 auto AST = buildASTFromCode("void g(const int&); void f() { int x; g(x); }"); 503 auto Results = 504 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 505 EXPECT_FALSE(isMutated(Results, AST.get())); 506 507 AST = buildASTFromCode("typedef const int& CIntRef;" 508 "void g(CIntRef); void f() { int x; g(x); }"); 509 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 510 EXPECT_FALSE(isMutated(Results, AST.get())); 511 512 AST = buildASTFromCode("template <class T> using CTRef = const T&;" 513 "void g(CTRef<int>); void f() { int x; g(x); }"); 514 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 515 EXPECT_FALSE(isMutated(Results, AST.get())); 516 517 AST = 518 buildASTFromCode("template <class T> struct identity { using type = T; };" 519 "template <class T, class U = const T&>" 520 "void g(typename identity<U>::type);" 521 "void f() { int x; g<int>(x); }"); 522 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 523 EXPECT_FALSE(isMutated(Results, AST.get())); 524 525 AST = buildASTFromCode( 526 "struct A {}; A operator+(const A&, int); void f() { A x; x + 1; }"); 527 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 528 EXPECT_FALSE(isMutated(Results, AST.get())); 529 530 AST = buildASTFromCode( 531 "void f() { struct A { A(const int&); }; int x; A y(x); }"); 532 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 533 EXPECT_FALSE(isMutated(Results, AST.get())); 534 535 AST = buildASTFromCode( 536 "void f() { struct A { A(); A(const A&); }; A x; A y(x); }"); 537 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 538 EXPECT_FALSE(isMutated(Results, AST.get())); 539 } 540 541 TEST(ExprMutationAnalyzerTest, ByNonConstRRefArgument) { 542 auto AST = buildASTFromCode( 543 "void g(int&&); void f() { int x; g(static_cast<int &&>(x)); }"); 544 auto Results = 545 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 546 EXPECT_THAT(mutatedBy(Results, AST.get()), 547 ElementsAre("g(static_cast<int &&>(x))")); 548 549 AST = buildASTFromCode("struct A {}; A operator+(A&&, int);" 550 "void f() { A x; static_cast<A &&>(x) + 1; }"); 551 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 552 EXPECT_THAT(mutatedBy(Results, AST.get()), 553 ElementsAre("static_cast<A &&>(x) + 1")); 554 555 AST = buildASTFromCode("void f() { struct A { A(int&&); }; " 556 "int x; A y(static_cast<int &&>(x)); }"); 557 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 558 EXPECT_THAT(mutatedBy(Results, AST.get()), 559 ElementsAre("static_cast<int &&>(x)")); 560 561 AST = buildASTFromCode("void f() { struct A { A(); A(A&&); }; " 562 "A x; A y(static_cast<A &&>(x)); }"); 563 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 564 EXPECT_THAT(mutatedBy(Results, AST.get()), 565 ElementsAre("static_cast<A &&>(x)")); 566 } 567 568 TEST(ExprMutationAnalyzerTest, ByConstRRefArgument) { 569 auto AST = buildASTFromCode( 570 "void g(const int&&); void f() { int x; g(static_cast<int&&>(x)); }"); 571 auto Results = 572 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 573 EXPECT_THAT(mutatedBy(Results, AST.get()), 574 ElementsAre("static_cast<int &&>(x)")); 575 576 AST = buildASTFromCode("struct A {}; A operator+(const A&&, int);" 577 "void f() { A x; static_cast<A&&>(x) + 1; }"); 578 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 579 EXPECT_THAT(mutatedBy(Results, AST.get()), 580 ElementsAre("static_cast<A &&>(x)")); 581 582 AST = buildASTFromCode("void f() { struct A { A(const int&&); }; " 583 "int x; A y(static_cast<int&&>(x)); }"); 584 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 585 EXPECT_THAT(mutatedBy(Results, AST.get()), 586 ElementsAre("static_cast<int &&>(x)")); 587 588 AST = buildASTFromCode("void f() { struct A { A(); A(const A&&); }; " 589 "A x; A y(static_cast<A&&>(x)); }"); 590 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 591 EXPECT_THAT(mutatedBy(Results, AST.get()), 592 ElementsAre("static_cast<A &&>(x)")); 593 } 594 595 // section: explicit std::move and std::forward testing 596 597 TEST(ExprMutationAnalyzerTest, Move) { 598 auto AST = buildASTFromCode(StdRemoveReference + StdMove + 599 "void f() { struct A {}; A x; std::move(x); }"); 600 auto Results = 601 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 602 EXPECT_FALSE(isMutated(Results, AST.get())); 603 604 AST = buildASTFromCode(StdRemoveReference + StdMove + 605 "void f() { struct A {}; A x, y; std::move(x) = y; }"); 606 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 607 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x) = y")); 608 609 AST = buildASTFromCode(StdRemoveReference + StdMove + 610 "void f() { int x, y; y = std::move(x); }"); 611 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 612 EXPECT_FALSE(isMutated(Results, AST.get())); 613 614 AST = 615 buildASTFromCode(StdRemoveReference + StdMove + 616 "struct S { S(); S(const S&); S& operator=(const S&); };" 617 "void f() { S x, y; y = std::move(x); }"); 618 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 619 EXPECT_FALSE(isMutated(Results, AST.get())); 620 621 AST = buildASTFromCode(StdRemoveReference + StdMove + 622 "struct S { S(); S(S&&); S& operator=(S&&); };" 623 "void f() { S x, y; y = std::move(x); }"); 624 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 625 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 626 627 AST = buildASTFromCode(StdRemoveReference + StdMove + 628 "struct S { S(); S(const S&); S(S&&);" 629 "S& operator=(const S&); S& operator=(S&&); };" 630 "void f() { S x, y; y = std::move(x); }"); 631 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 632 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 633 634 AST = buildASTFromCode(StdRemoveReference + StdMove + 635 "struct S { S(); S(const S&); S(S&&);" 636 "S& operator=(const S&); S& operator=(S&&); };" 637 "void f() { const S x; S y; y = std::move(x); }"); 638 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 639 EXPECT_FALSE(isMutated(Results, AST.get())); 640 641 AST = buildASTFromCode(StdRemoveReference + StdMove + 642 "struct S { S(); S& operator=(S); };" 643 "void f() { S x, y; y = std::move(x); }"); 644 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 645 EXPECT_FALSE(isMutated(Results, AST.get())); 646 647 AST = buildASTFromCode(StdRemoveReference + StdMove + 648 "struct S{}; void f() { S x, y; y = std::move(x); }"); 649 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 650 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 651 652 AST = buildASTFromCode( 653 StdRemoveReference + StdMove + 654 "struct S{}; void f() { const S x; S y; y = std::move(x); }"); 655 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 656 EXPECT_FALSE(isMutated(Results, AST.get())); 657 } 658 659 TEST(ExprMutationAnalyzerTest, Forward) { 660 auto AST = 661 buildASTFromCode(StdRemoveReference + StdForward + 662 "void f() { struct A {}; A x; std::forward<A &>(x); }"); 663 auto Results = 664 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 665 EXPECT_FALSE(isMutated(Results, AST.get())); 666 667 AST = buildASTFromCode( 668 StdRemoveReference + StdForward + 669 "void f() { struct A {}; A x, y; std::forward<A &>(x) = y; }"); 670 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 671 EXPECT_THAT(mutatedBy(Results, AST.get()), 672 ElementsAre("std::forward<A &>(x) = y")); 673 } 674 675 // section: template constellations that prohibit reasoning about modifications 676 // as it depends on instantiations. 677 678 TEST(ExprMutationAnalyzerTest, CallUnresolved) { 679 auto AST = 680 buildASTFromCodeWithArgs("template <class T> void f() { T x; g(x); }", 681 {"-fno-delayed-template-parsing"}); 682 auto Results = 683 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 684 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 685 686 AST = 687 buildASTFromCodeWithArgs("template <int N> void f() { char x[N]; g(x); }", 688 {"-fno-delayed-template-parsing"}); 689 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 690 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 691 692 AST = buildASTFromCodeWithArgs( 693 "template <class T> void f(T t) { int x; g(t, x); }", 694 {"-fno-delayed-template-parsing"}); 695 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 696 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(t, x)")); 697 698 AST = buildASTFromCodeWithArgs( 699 "template <class T> void f(T t) { int x; t.mf(x); }", 700 {"-fno-delayed-template-parsing"}); 701 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 702 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("t.mf(x)")); 703 704 AST = buildASTFromCodeWithArgs( 705 "template <class T> struct S;" 706 "template <class T> void f() { S<T> s; int x; s.mf(x); }", 707 {"-fno-delayed-template-parsing"}); 708 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 709 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)")); 710 711 AST = buildASTFromCodeWithArgs( 712 "struct S { template <class T> void mf(); };" 713 "template <class T> void f(S s) { int x; s.mf<T>(x); }", 714 {"-fno-delayed-template-parsing"}); 715 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 716 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf<T>(x)")); 717 718 AST = buildASTFromCodeWithArgs("template <class F>" 719 "void g(F f) { int x; f(x); } ", 720 {"-fno-delayed-template-parsing"}); 721 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 722 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f(x)")); 723 724 AST = buildASTFromCodeWithArgs( 725 "template <class T> void f() { int x; (void)T(x); }", 726 {"-fno-delayed-template-parsing"}); 727 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 728 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("T(x)")); 729 } 730 731 // section: return values 732 733 TEST(ExprMutationAnalyzerTest, ReturnAsValue) { 734 auto AST = buildASTFromCode("int f() { int x; return x; }"); 735 auto Results = 736 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 737 EXPECT_FALSE(isMutated(Results, AST.get())); 738 739 AST = buildASTFromCode("int* f() { int* x; return x; }"); 740 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 741 EXPECT_FALSE(isMutated(Results, AST.get())); 742 743 AST = buildASTFromCode("typedef int* IntPtr;" 744 "IntPtr f() { int* x; return x; }"); 745 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 746 EXPECT_FALSE(isMutated(Results, AST.get())); 747 } 748 749 TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) { 750 const auto AST = buildASTFromCode("int& f() { int x; return x; }"); 751 const auto Results = 752 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 753 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;")); 754 } 755 756 TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) { 757 const auto AST = buildASTFromCode("const int& f() { int x; return x; }"); 758 const auto Results = 759 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 760 EXPECT_FALSE(isMutated(Results, AST.get())); 761 } 762 763 TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRRef) { 764 const auto AST = 765 buildASTFromCode("int&& f() { int x; return static_cast<int &&>(x); }"); 766 const auto Results = 767 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 768 EXPECT_THAT(mutatedBy(Results, AST.get()), 769 ElementsAre("static_cast<int &&>(x)")); 770 } 771 772 TEST(ExprMutationAnalyzerTest, ReturnAsConstRRef) { 773 const auto AST = buildASTFromCode( 774 "const int&& f() { int x; return static_cast<int&&>(x); }"); 775 const auto Results = 776 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 777 EXPECT_THAT(mutatedBy(Results, AST.get()), 778 ElementsAre("static_cast<int &&>(x)")); 779 } 780 781 // section: taking the address of a variable and pointers 782 783 TEST(ExprMutationAnalyzerTest, TakeAddress) { 784 const auto AST = buildASTFromCode("void g(int*); void f() { int x; g(&x); }"); 785 const auto Results = 786 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 787 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x")); 788 } 789 790 TEST(ExprMutationAnalyzerTest, ArrayToPointerDecay) { 791 const auto AST = 792 buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }"); 793 const auto Results = 794 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 795 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 796 } 797 798 TEST(ExprMutationAnalyzerTest, TemplateWithArrayToPointerDecay) { 799 const auto AST = buildASTFromCodeWithArgs( 800 "template <typename T> struct S { static constexpr int v = 8; };" 801 "template <> struct S<int> { static constexpr int v = 4; };" 802 "void g(char*);" 803 "template <typename T> void f() { char x[S<T>::v]; g(x); }" 804 "template <> void f<int>() { char y[S<int>::v]; g(y); }", 805 {"-fno-delayed-template-parsing"}); 806 const auto ResultsX = 807 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 808 EXPECT_THAT(mutatedBy(ResultsX, AST.get()), ElementsAre("g(x)")); 809 const auto ResultsY = 810 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 811 EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y")); 812 } 813 814 // section: special case: all created references are non-mutating themself 815 // and therefore all become 'const'/the value is not modified! 816 817 TEST(ExprMutationAnalyzerTest, FollowRefModified) { 818 auto AST = buildASTFromCode( 819 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " 820 "int& r3 = r2; r3 = 10; }"); 821 auto Results = 822 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 823 EXPECT_THAT(mutatedBy(Results, AST.get()), 824 ElementsAre("r0", "r1", "r2", "r3", "r3 = 10")); 825 826 AST = buildASTFromCode("typedef int& IntRefX;" 827 "using IntRefY = int&;" 828 "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;" 829 "decltype((x)) r2 = r1; r2 = 10; }"); 830 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 831 EXPECT_THAT(mutatedBy(Results, AST.get()), 832 ElementsAre("r0", "r1", "r2", "r2 = 10")); 833 } 834 835 TEST(ExprMutationAnalyzerTest, FollowRefNotModified) { 836 auto AST = buildASTFromCode( 837 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " 838 "int& r3 = r2; int& r4 = r3; int& r5 = r4;}"); 839 auto Results = 840 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 841 EXPECT_FALSE(isMutated(Results, AST.get())); 842 843 AST = buildASTFromCode("void f() { int x; int& r0 = x; const int& r1 = r0;}"); 844 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 845 EXPECT_FALSE(isMutated(Results, AST.get())); 846 847 AST = buildASTFromCode("typedef const int& CIntRefX;" 848 "using CIntRefY = const int&;" 849 "void f() { int x; int& r0 = x; CIntRefX r1 = r0;" 850 "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}"); 851 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 852 EXPECT_FALSE(isMutated(Results, AST.get())); 853 } 854 855 TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) { 856 const auto AST = buildASTFromCode( 857 "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }"); 858 const auto Results = 859 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 860 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10")); 861 } 862 863 TEST(ExprMutationAnalyzerTest, FollowConditionalRefNotModified) { 864 const auto AST = 865 buildASTFromCode("void f() { int x, y; bool b; int& r = b ? x : y; }"); 866 const auto Results = 867 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 868 EXPECT_FALSE(isMutated(Results, AST.get())); 869 } 870 871 TEST(ExprMutationAnalyzerTest, FollowFuncArgModified) { 872 auto AST = buildASTFromCode("template <class T> void g(T&& t) { t = 10; }" 873 "void f() { int x; g(x); }"); 874 auto Results = 875 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 876 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 877 878 AST = buildASTFromCode( 879 "void h(int&);" 880 "template <class... Args> void g(Args&&... args) { h(args...); }" 881 "void f() { int x; g(x); }"); 882 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 883 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 884 885 AST = buildASTFromCode( 886 "void h(int&, int);" 887 "template <class... Args> void g(Args&&... args) { h(args...); }" 888 "void f() { int x, y; g(x, y); }"); 889 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 890 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x, y)")); 891 Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 892 EXPECT_FALSE(isMutated(Results, AST.get())); 893 894 AST = buildASTFromCode( 895 "void h(int, int&);" 896 "template <class... Args> void g(Args&&... args) { h(args...); }" 897 "void f() { int x, y; g(y, x); }"); 898 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 899 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(y, x)")); 900 Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 901 EXPECT_FALSE(isMutated(Results, AST.get())); 902 903 AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t = 10; } };" 904 "void f() { int x; S s(x); }"); 905 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 906 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 907 908 AST = buildASTFromCode( 909 "struct S { template <class T> S(T&& t) : m(++t) { } int m; };" 910 "void f() { int x; S s(x); }"); 911 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 912 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 913 914 AST = buildASTFromCode("template <class U> struct S {" 915 "template <class T> S(T&& t) : m(++t) { } U m; };" 916 "void f() { int x; S<int> s(x); }"); 917 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 918 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 919 920 AST = buildASTFromCode(StdRemoveReference + StdForward + 921 "template <class... Args> void u(Args&...);" 922 "template <class... Args> void h(Args&&... args)" 923 "{ u(std::forward<Args>(args)...); }" 924 "template <class... Args> void g(Args&&... args)" 925 "{ h(std::forward<Args>(args)...); }" 926 "void f() { int x; g(x); }"); 927 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 928 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 929 } 930 931 TEST(ExprMutationAnalyzerTest, FollowFuncArgNotModified) { 932 auto AST = buildASTFromCode("template <class T> void g(T&&) {}" 933 "void f() { int x; g(x); }"); 934 auto Results = 935 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 936 EXPECT_FALSE(isMutated(Results, AST.get())); 937 938 AST = buildASTFromCode("template <class T> void g(T&& t) { t; }" 939 "void f() { int x; g(x); }"); 940 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 941 EXPECT_FALSE(isMutated(Results, AST.get())); 942 943 AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}" 944 "void f() { int x; g(x); }"); 945 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 946 EXPECT_FALSE(isMutated(Results, AST.get())); 947 948 AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}" 949 "void f() { int y, x; g(y, x); }"); 950 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 951 EXPECT_FALSE(isMutated(Results, AST.get())); 952 953 AST = buildASTFromCode( 954 "void h(int, int&);" 955 "template <class... Args> void g(Args&&... args) { h(args...); }" 956 "void f() { int x, y; g(x, y); }"); 957 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 958 EXPECT_FALSE(isMutated(Results, AST.get())); 959 960 AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t; } };" 961 "void f() { int x; S s(x); }"); 962 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 963 EXPECT_FALSE(isMutated(Results, AST.get())); 964 965 AST = buildASTFromCode( 966 "struct S { template <class T> S(T&& t) : m(t) { } int m; };" 967 "void f() { int x; S s(x); }"); 968 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 969 EXPECT_FALSE(isMutated(Results, AST.get())); 970 971 AST = buildASTFromCode("template <class U> struct S {" 972 "template <class T> S(T&& t) : m(t) { } U m; };" 973 "void f() { int x; S<int> s(x); }"); 974 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 975 EXPECT_FALSE(isMutated(Results, AST.get())); 976 977 AST = buildASTFromCode(StdRemoveReference + StdForward + 978 "template <class... Args> void u(Args...);" 979 "template <class... Args> void h(Args&&... args)" 980 "{ u(std::forward<Args>(args)...); }" 981 "template <class... Args> void g(Args&&... args)" 982 "{ h(std::forward<Args>(args)...); }" 983 "void f() { int x; g(x); }"); 984 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 985 EXPECT_FALSE(isMutated(Results, AST.get())); 986 } 987 988 // section: builtin arrays 989 990 TEST(ExprMutationAnalyzerTest, ArrayElementModified) { 991 const auto AST = buildASTFromCode("void f() { int x[2]; x[0] = 10; }"); 992 const auto Results = 993 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 994 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10")); 995 } 996 997 TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) { 998 const auto AST = buildASTFromCode("void f() { int x[2]; x[0]; }"); 999 const auto Results = 1000 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1001 EXPECT_FALSE(isMutated(Results, AST.get())); 1002 } 1003 1004 // section: member modifications 1005 1006 TEST(ExprMutationAnalyzerTest, NestedMemberModified) { 1007 auto AST = 1008 buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " 1009 "struct C { B vb; }; C x; x.vb.va.vi = 10; }"); 1010 auto Results = 1011 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1012 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10")); 1013 1014 AST = buildASTFromCodeWithArgs( 1015 "template <class T> void f() { T x; x.y.z = 10; }", 1016 {"-fno-delayed-template-parsing"}); 1017 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1018 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); 1019 1020 AST = buildASTFromCodeWithArgs( 1021 "template <class T> struct S;" 1022 "template <class T> void f() { S<T> x; x.y.z = 10; }", 1023 {"-fno-delayed-template-parsing"}); 1024 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1025 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); 1026 } 1027 1028 TEST(ExprMutationAnalyzerTest, NestedMemberNotModified) { 1029 auto AST = 1030 buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " 1031 "struct C { B vb; }; C x; x.vb.va.vi; }"); 1032 auto Results = 1033 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1034 EXPECT_FALSE(isMutated(Results, AST.get())); 1035 1036 AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.y.z; }", 1037 {"-fno-delayed-template-parsing"}); 1038 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1039 EXPECT_FALSE(isMutated(Results, AST.get())); 1040 1041 AST = 1042 buildASTFromCodeWithArgs("template <class T> struct S;" 1043 "template <class T> void f() { S<T> x; x.y.z; }", 1044 {"-fno-delayed-template-parsing"}); 1045 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1046 EXPECT_FALSE(isMutated(Results, AST.get())); 1047 } 1048 1049 // section: casts 1050 1051 TEST(ExprMutationAnalyzerTest, CastToValue) { 1052 const auto AST = 1053 buildASTFromCode("void f() { int x; static_cast<double>(x); }"); 1054 const auto Results = 1055 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1056 EXPECT_FALSE(isMutated(Results, AST.get())); 1057 } 1058 1059 TEST(ExprMutationAnalyzerTest, CastToRefModified) { 1060 auto AST = 1061 buildASTFromCode("void f() { int x; static_cast<int &>(x) = 10; }"); 1062 auto Results = 1063 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1064 EXPECT_THAT(mutatedBy(Results, AST.get()), 1065 ElementsAre("static_cast<int &>(x)")); 1066 1067 AST = buildASTFromCode("typedef int& IntRef;" 1068 "void f() { int x; static_cast<IntRef>(x) = 10; }"); 1069 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1070 EXPECT_THAT(mutatedBy(Results, AST.get()), 1071 ElementsAre("static_cast<IntRef>(x)")); 1072 } 1073 1074 TEST(ExprMutationAnalyzerTest, CastToRefNotModified) { 1075 const auto AST = 1076 buildASTFromCode("void f() { int x; static_cast<int&>(x); }"); 1077 const auto Results = 1078 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1079 EXPECT_THAT(mutatedBy(Results, AST.get()), 1080 ElementsAre("static_cast<int &>(x)")); 1081 } 1082 1083 TEST(ExprMutationAnalyzerTest, CastToConstRef) { 1084 auto AST = 1085 buildASTFromCode("void f() { int x; static_cast<const int&>(x); }"); 1086 auto Results = 1087 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1088 EXPECT_FALSE(isMutated(Results, AST.get())); 1089 1090 AST = buildASTFromCode("typedef const int& CIntRef;" 1091 "void f() { int x; static_cast<CIntRef>(x); }"); 1092 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1093 EXPECT_FALSE(isMutated(Results, AST.get())); 1094 } 1095 1096 // section: comma expressions 1097 1098 TEST(ExprMutationAnalyzerTest, CommaExprWithAnAssigment) { 1099 const auto AST = buildASTFromCodeWithArgs( 1100 "void f() { int x; int y; (x, y) = 5; }", {"-Wno-unused-value"}); 1101 const auto Results = 1102 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 1103 EXPECT_TRUE(isMutated(Results, AST.get())); 1104 } 1105 1106 TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) { 1107 const auto AST = buildASTFromCodeWithArgs( 1108 "void f() { int x; int y; (x, y)++; }", {"-Wno-unused-value"}); 1109 const auto Results = 1110 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 1111 EXPECT_TRUE(isMutated(Results, AST.get())); 1112 } 1113 1114 TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) { 1115 const auto AST = buildASTFromCodeWithArgs( 1116 "class A { public: int mem; void f() { mem ++; } };" 1117 "void fn() { A o1, o2; (o1, o2).f(); }", 1118 {"-Wno-unused-value"}); 1119 const auto Results = 1120 match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext()); 1121 EXPECT_TRUE(isMutated(Results, AST.get())); 1122 } 1123 1124 TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) { 1125 const auto AST = buildASTFromCodeWithArgs( 1126 "class A { public: int mem; void f() const { } };" 1127 "void fn() { A o1, o2; (o1, o2).f(); }", 1128 {"-Wno-unused-value"}); 1129 const auto Results = 1130 match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext()); 1131 EXPECT_FALSE(isMutated(Results, AST.get())); 1132 } 1133 1134 TEST(ExprMutationAnalyzerTest, CommaExprWithCallExpr) { 1135 const auto AST = 1136 buildASTFromCodeWithArgs("class A { public: int mem; void f(A &O1) {} };" 1137 "void fn() { A o1, o2; o2.f((o2, o1)); }", 1138 {"-Wno-unused-value"}); 1139 const auto Results = 1140 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 1141 EXPECT_TRUE(isMutated(Results, AST.get())); 1142 } 1143 1144 TEST(ExprMutationAnalyzerTest, CommaExprWithCallUnresolved) { 1145 auto AST = buildASTFromCodeWithArgs( 1146 "template <class T> struct S;" 1147 "template <class T> void f() { S<T> s; int x, y; s.mf((y, x)); }", 1148 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1149 auto Results = 1150 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1151 EXPECT_TRUE(isMutated(Results, AST.get())); 1152 1153 AST = buildASTFromCodeWithArgs( 1154 "template <class T> void f(T t) { int x, y; g(t, (y, x)); }", 1155 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1156 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1157 EXPECT_TRUE(isMutated(Results, AST.get())); 1158 } 1159 1160 TEST(ExprMutationAnalyzerTest, CommaExprParmRef) { 1161 const auto AST = 1162 buildASTFromCodeWithArgs("class A { public: int mem;};" 1163 "extern void fn(A &o1);" 1164 "void fn2 () { A o1, o2; fn((o2, o1)); } ", 1165 {"-Wno-unused-value"}); 1166 const auto Results = 1167 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 1168 EXPECT_TRUE(isMutated(Results, AST.get())); 1169 } 1170 1171 TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) { 1172 const auto AST = buildASTFromCodeWithArgs("class A { public: int mem;};" 1173 "void fn () { A o1, o2;" 1174 "void *addr = &(o2, o1); } ", 1175 {"-Wno-unused-value"}); 1176 const auto Results = 1177 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 1178 EXPECT_TRUE(isMutated(Results, AST.get())); 1179 } 1180 1181 TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsValue) { 1182 auto AST = buildASTFromCodeWithArgs("int f() { int x, y; return (x, y); }", 1183 {"-Wno-unused-value"}); 1184 auto Results = 1185 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 1186 EXPECT_FALSE(isMutated(Results, AST.get())); 1187 } 1188 1189 TEST(ExprMutationAnalyzerTest, CommaEpxrAsReturnAsNonConstRef) { 1190 const auto AST = buildASTFromCodeWithArgs( 1191 "int& f() { int x, y; return (y, x); }", {"-Wno-unused-value"}); 1192 const auto Results = 1193 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1194 EXPECT_TRUE(isMutated(Results, AST.get())); 1195 } 1196 1197 TEST(ExprMutationAnalyzerTest, CommaExprAsArrayToPointerDecay) { 1198 const auto AST = 1199 buildASTFromCodeWithArgs("void g(int*); " 1200 "void f() { int x[2], y[2]; g((y, x)); }", 1201 {"-Wno-unused-value"}); 1202 const auto Results = 1203 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1204 EXPECT_TRUE(isMutated(Results, AST.get())); 1205 } 1206 1207 TEST(ExprMutationAnalyzerTest, CommaExprAsUniquePtr) { 1208 const std::string UniquePtrDef = "template <class T> struct UniquePtr {" 1209 " UniquePtr();" 1210 " UniquePtr(const UniquePtr&) = delete;" 1211 " T& operator*() const;" 1212 " T* operator->() const;" 1213 "};"; 1214 const auto AST = buildASTFromCodeWithArgs( 1215 UniquePtrDef + "template <class T> void f() " 1216 "{ UniquePtr<T> x; UniquePtr<T> y;" 1217 " (y, x)->mf(); }", 1218 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1219 const auto Results = 1220 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1221 EXPECT_TRUE(isMutated(Results, AST.get())); 1222 } 1223 1224 TEST(ExprMutationAnalyzerTest, CommaNestedConditional) { 1225 const std::string Code = "void f() { int x, y = 42;" 1226 " y, (true ? x : y) = 42; }"; 1227 const auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"}); 1228 const auto Results = 1229 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1230 EXPECT_THAT(mutatedBy(Results, AST.get()), 1231 ElementsAre("(true ? x : y) = 42")); 1232 } 1233 1234 // section: lambda captures 1235 1236 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) { 1237 const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }"); 1238 const auto Results = 1239 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1240 EXPECT_FALSE(isMutated(Results, AST.get())); 1241 } 1242 1243 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) { 1244 const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }"); 1245 const auto Results = 1246 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1247 EXPECT_FALSE(isMutated(Results, AST.get())); 1248 } 1249 1250 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) { 1251 const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }"); 1252 const auto Results = 1253 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1254 EXPECT_THAT(mutatedBy(Results, AST.get()), 1255 ElementsAre(ResultOf(removeSpace, "[&](){x=10;}"))); 1256 } 1257 1258 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) { 1259 const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }"); 1260 const auto Results = 1261 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1262 EXPECT_THAT(mutatedBy(Results, AST.get()), 1263 ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}"))); 1264 } 1265 1266 // section: range-for loops 1267 1268 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) { 1269 auto AST = 1270 buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }"); 1271 auto Results = 1272 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1273 EXPECT_THAT(mutatedBy(Results, AST.get()), 1274 ElementsAre("for (int &e : x)\n e = 10;")); 1275 1276 AST = buildASTFromCode("typedef int& IntRef;" 1277 "void f() { int x[2]; for (IntRef e : x) e = 10; }"); 1278 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1279 EXPECT_THAT(mutatedBy(Results, AST.get()), 1280 ElementsAre("for (IntRef e : x)\n e = 10;")); 1281 } 1282 1283 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModifiedByImplicitInit) { 1284 const auto AST = 1285 buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }"); 1286 const auto Results = 1287 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1288 EXPECT_TRUE(isMutated(Results, AST.get())); 1289 } 1290 1291 TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) { 1292 auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }"); 1293 auto Results = 1294 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1295 EXPECT_FALSE(isMutated(Results, AST.get())); 1296 1297 AST = 1298 buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }"); 1299 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1300 EXPECT_TRUE(isMutated(Results, AST.get())); 1301 1302 AST = buildASTFromCode( 1303 "typedef int* IntPtr;" 1304 "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }"); 1305 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1306 EXPECT_TRUE(isMutated(Results, AST.get())); 1307 } 1308 1309 TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) { 1310 auto AST = 1311 buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }"); 1312 auto Results = 1313 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1314 EXPECT_FALSE(isMutated(Results, AST.get())); 1315 1316 AST = buildASTFromCode("typedef const int& CIntRef;" 1317 "void f() { int x[2]; for (CIntRef e : x) e; }"); 1318 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1319 EXPECT_FALSE(isMutated(Results, AST.get())); 1320 } 1321 1322 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) { 1323 const auto AST = 1324 buildASTFromCode("struct V { int* begin(); int* end(); };" 1325 "void f() { V x; for (int& e : x) e = 10; }"); 1326 const auto Results = 1327 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1328 EXPECT_THAT(mutatedBy(Results, AST.get()), 1329 ElementsAre("for (int &e : x)\n e = 10;")); 1330 } 1331 1332 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) { 1333 const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };" 1334 "void f() { V x; for (int& e : x) e; }"); 1335 const auto Results = 1336 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1337 EXPECT_TRUE(isMutated(Results, AST.get())); 1338 } 1339 1340 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) { 1341 const auto AST = buildASTFromCode( 1342 "struct V { const int* begin() const; const int* end() const; };" 1343 "void f() { V x; for (int e : x) e; }"); 1344 const auto Results = 1345 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1346 EXPECT_FALSE(isMutated(Results, AST.get())); 1347 } 1348 1349 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) { 1350 const auto AST = buildASTFromCode( 1351 "struct V { const int* begin() const; const int* end() const; };" 1352 "void f() { V x; for (const int& e : x) e; }"); 1353 const auto Results = 1354 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1355 EXPECT_FALSE(isMutated(Results, AST.get())); 1356 } 1357 1358 // section: unevaluated expressions 1359 1360 TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) { 1361 auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }"); 1362 auto Results = 1363 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1364 EXPECT_FALSE(isMutated(Results, AST.get())); 1365 1366 AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }"); 1367 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1368 EXPECT_FALSE(isMutated(Results, AST.get())); 1369 1370 AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }"); 1371 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1372 EXPECT_FALSE(isMutated(Results, AST.get())); 1373 1374 AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }"); 1375 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1376 EXPECT_FALSE(isMutated(Results, AST.get())); 1377 1378 AST = buildASTFromCode("void f() { int x; alignof(x = 10); }"); 1379 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1380 EXPECT_FALSE(isMutated(Results, AST.get())); 1381 1382 AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }"); 1383 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1384 EXPECT_FALSE(isMutated(Results, AST.get())); 1385 1386 AST = buildASTFromCodeWithArgs("namespace std { class type_info; }" 1387 "void f() { int x; typeid(x = 10); }", 1388 {"-frtti"}); 1389 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1390 EXPECT_FALSE(isMutated(Results, AST.get())); 1391 1392 AST = buildASTFromCode( 1393 "void f() { int x; _Generic(x = 10, int: 0, default: 1); }"); 1394 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1395 EXPECT_FALSE(isMutated(Results, AST.get())); 1396 } 1397 1398 TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) { 1399 auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }"); 1400 auto Results = 1401 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1402 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++")); 1403 1404 AST = buildASTFromCodeWithArgs( 1405 "namespace std { class type_info; }" 1406 "struct A { virtual ~A(); }; struct B : A {};" 1407 "struct X { A& f(); }; void f() { X x; typeid(x.f()); }", 1408 {"-frtti"}); 1409 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1410 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()")); 1411 } 1412 1413 // section: special case: smartpointers 1414 1415 TEST(ExprMutationAnalyzerTest, UniquePtr) { 1416 const std::string UniquePtrDef = 1417 "template <class T> struct UniquePtr {" 1418 " UniquePtr();" 1419 " UniquePtr(const UniquePtr&) = delete;" 1420 " UniquePtr(UniquePtr&&);" 1421 " UniquePtr& operator=(const UniquePtr&) = delete;" 1422 " UniquePtr& operator=(UniquePtr&&);" 1423 " T& operator*() const;" 1424 " T* operator->() const;" 1425 "};"; 1426 1427 auto AST = buildASTFromCode(UniquePtrDef + 1428 "void f() { UniquePtr<int> x; *x = 10; }"); 1429 auto Results = 1430 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1431 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10")); 1432 1433 AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr<int> x; *x; }"); 1434 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1435 EXPECT_FALSE(isMutated(Results, AST.get())); 1436 1437 AST = buildASTFromCode(UniquePtrDef + 1438 "void f() { UniquePtr<const int> x; *x; }"); 1439 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1440 EXPECT_FALSE(isMutated(Results, AST.get())); 1441 1442 AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };" 1443 "void f() { UniquePtr<S> x; x->v; }"); 1444 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1445 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1446 1447 AST = buildASTFromCode(UniquePtrDef + 1448 "struct S { int v; };" 1449 "void f() { UniquePtr<const S> x; x->v; }"); 1450 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1451 EXPECT_FALSE(isMutated(Results, AST.get())); 1452 1453 AST = 1454 buildASTFromCode(UniquePtrDef + "struct S { void mf(); };" 1455 "void f() { UniquePtr<S> x; x->mf(); }"); 1456 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1457 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1458 1459 AST = buildASTFromCode(UniquePtrDef + 1460 "struct S { void mf() const; };" 1461 "void f() { UniquePtr<const S> x; x->mf(); }"); 1462 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1463 EXPECT_FALSE(isMutated(Results, AST.get())); 1464 1465 AST = buildASTFromCodeWithArgs( 1466 UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }", 1467 {"-fno-delayed-template-parsing"}); 1468 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1469 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()")); 1470 } 1471 1472 // section: complex problems detected on real code 1473 1474 TEST(ExprMutationAnalyzerTest, UnevaluatedContext) { 1475 const std::string Example = 1476 "template <typename T>" 1477 "struct to_construct : T { to_construct(int &j) {} };" 1478 "template <typename T>" 1479 "void placement_new_in_unique_ptr() { int x = 0;" 1480 " new to_construct<T>(x);" 1481 "}"; 1482 auto AST = 1483 buildASTFromCodeWithArgs(Example, {"-fno-delayed-template-parsing"}); 1484 auto Results = 1485 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1486 EXPECT_TRUE(isMutated(Results, AST.get())); 1487 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(x)")); 1488 } 1489 1490 TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) { 1491 const std::string Reproducer = 1492 "namespace std {" 1493 "template <class T> T &forward(T &A) { return static_cast<T&&>(A); }" 1494 "template <class T> struct __bind {" 1495 " T f;" 1496 " template <class V> __bind(T v, V &&) : f(forward(v)) {}" 1497 "};" 1498 "}" 1499 "void f() {" 1500 " int x = 42;" 1501 " auto Lambda = [] {};" 1502 " std::__bind<decltype(Lambda)>(Lambda, x);" 1503 "}"; 1504 auto AST11 = buildASTFromCodeWithArgs(Reproducer, {"-std=c++11"}); 1505 auto Results11 = 1506 match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext()); 1507 EXPECT_FALSE(isMutated(Results11, AST11.get())); 1508 } 1509 } // namespace clang 1510