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 // Section: overloaded operators 288 289 TEST(ExprMutationAnalyzerTest, NonConstOperator) { 290 const auto AST = buildASTFromCode( 291 "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }"); 292 const auto Results = 293 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 294 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10")); 295 } 296 297 TEST(ExprMutationAnalyzerTest, ConstOperator) { 298 const auto AST = buildASTFromCode( 299 "void f() { struct Foo { int operator()() const; }; Foo x; x(); }"); 300 const auto Results = 301 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 302 EXPECT_FALSE(isMutated(Results, AST.get())); 303 } 304 305 TEST(ExprMutationAnalyzerTest, UnresolvedOperator) { 306 const auto AST = buildASTFromCodeWithArgs( 307 "template <typename Stream> void input_operator_template() {" 308 "Stream x; unsigned y = 42;" 309 "x >> y; }", 310 {"-fno-delayed-template-parsing"}); 311 const auto Results = 312 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 313 EXPECT_TRUE(isMutated(Results, AST.get())); 314 } 315 316 // Section: expression as call argument 317 318 TEST(ExprMutationAnalyzerTest, ByValueArgument) { 319 auto AST = buildASTFromCode("void g(int); void f() { int x; g(x); }"); 320 auto Results = 321 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 322 EXPECT_FALSE(isMutated(Results, AST.get())); 323 324 AST = buildASTFromCode("void g(int*); void f() { int* x; g(x); }"); 325 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 326 EXPECT_FALSE(isMutated(Results, AST.get())); 327 328 AST = buildASTFromCode("typedef int* IntPtr;" 329 "void g(IntPtr); void f() { int* x; g(x); }"); 330 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 331 EXPECT_FALSE(isMutated(Results, AST.get())); 332 333 AST = buildASTFromCode( 334 "struct A {}; A operator+(A, int); void f() { A x; x + 1; }"); 335 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 336 EXPECT_FALSE(isMutated(Results, AST.get())); 337 338 AST = buildASTFromCode("void f() { struct A { A(int); }; int x; A y(x); }"); 339 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 340 EXPECT_FALSE(isMutated(Results, AST.get())); 341 342 AST = buildASTFromCode("struct A { A(); A& operator=(A); };" 343 "void f() { A x, y; y = x; }"); 344 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 345 EXPECT_FALSE(isMutated(Results, AST.get())); 346 347 AST = buildASTFromCode( 348 "template <int> struct A { A(); A(const A&); static void mf(A) {} };" 349 "void f() { A<0> x; A<0>::mf(x); }"); 350 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 351 EXPECT_FALSE(isMutated(Results, AST.get())); 352 } 353 354 TEST(ExprMutationAnalyzerTest, ByConstValueArgument) { 355 auto AST = buildASTFromCode("void g(const int); void f() { int x; g(x); }"); 356 auto Results = 357 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 358 EXPECT_FALSE(isMutated(Results, AST.get())); 359 360 AST = buildASTFromCode("void g(int* const); void f() { int* x; g(x); }"); 361 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 362 EXPECT_FALSE(isMutated(Results, AST.get())); 363 364 AST = buildASTFromCode("typedef int* const CIntPtr;" 365 "void g(CIntPtr); void f() { int* x; g(x); }"); 366 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 367 EXPECT_FALSE(isMutated(Results, AST.get())); 368 369 AST = buildASTFromCode( 370 "struct A {}; A operator+(const A, int); void f() { A x; x + 1; }"); 371 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 372 EXPECT_FALSE(isMutated(Results, AST.get())); 373 374 AST = buildASTFromCode( 375 "void f() { struct A { A(const int); }; int x; A y(x); }"); 376 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 377 EXPECT_FALSE(isMutated(Results, AST.get())); 378 379 AST = buildASTFromCode("template <int> struct A { A(); A(const A&);" 380 "static void mf(const A&) {} };" 381 "void f() { A<0> x; A<0>::mf(x); }"); 382 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 383 EXPECT_FALSE(isMutated(Results, AST.get())); 384 } 385 386 TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) { 387 auto AST = buildASTFromCode("void g(int&); void f() { int x; g(x); }"); 388 auto Results = 389 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 390 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 391 392 AST = buildASTFromCode("typedef int& IntRef;" 393 "void g(IntRef); void f() { int x; g(x); }"); 394 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 395 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 396 397 AST = buildASTFromCode("template <class T> using TRef = T&;" 398 "void g(TRef<int>); void f() { int x; g(x); }"); 399 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 400 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 401 402 AST = buildASTFromCode( 403 "template <class T> struct identity { using type = T; };" 404 "template <class T, class U = T&> void g(typename identity<U>::type);" 405 "void f() { int x; g<int>(x); }"); 406 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 407 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g<int>(x)")); 408 409 AST = buildASTFromCode("typedef int* IntPtr;" 410 "void g(IntPtr&); void f() { int* x; g(x); }"); 411 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 412 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 413 414 AST = buildASTFromCode("typedef int* IntPtr; typedef IntPtr& IntPtrRef;" 415 "void g(IntPtrRef); void f() { int* x; g(x); }"); 416 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 417 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 418 419 AST = buildASTFromCode( 420 "struct A {}; A operator+(A&, int); void f() { A x; x + 1; }"); 421 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 422 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1")); 423 424 AST = buildASTFromCode("void f() { struct A { A(int&); }; int x; A y(x); }"); 425 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 426 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 427 428 AST = buildASTFromCode("void f() { struct A { A(); A(A&); }; A x; A y(x); }"); 429 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 430 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 431 432 AST = buildASTFromCode( 433 "template <int> struct A { A(); A(const A&); static void mf(A&) {} };" 434 "void f() { A<0> x; A<0>::mf(x); }"); 435 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 436 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("A<0>::mf(x)")); 437 } 438 439 TEST(ExprMutationAnalyzerTest, ByNonConstRefArgumentFunctionTypeDependent) { 440 auto AST = buildASTFromCodeWithArgs( 441 "enum MyEnum { foo, bar };" 442 "void tryParser(unsigned& first, MyEnum Type) { first++, (void)Type; }" 443 "template <MyEnum Type> void parse() {" 444 " auto parser = [](unsigned& first) { first++; tryParser(first, Type); " 445 "};" 446 " unsigned x = 42;" 447 " parser(x);" 448 "}", 449 {"-fno-delayed-template-parsing"}); 450 auto Results = 451 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 452 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("parser(x)")); 453 } 454 455 TEST(ExprMutationAnalyzerTest, ByConstRefArgument) { 456 auto AST = buildASTFromCode("void g(const int&); void f() { int x; g(x); }"); 457 auto Results = 458 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 459 EXPECT_FALSE(isMutated(Results, AST.get())); 460 461 AST = buildASTFromCode("typedef const int& CIntRef;" 462 "void g(CIntRef); void f() { int x; g(x); }"); 463 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 464 EXPECT_FALSE(isMutated(Results, AST.get())); 465 466 AST = buildASTFromCode("template <class T> using CTRef = const T&;" 467 "void g(CTRef<int>); void f() { int x; g(x); }"); 468 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 469 EXPECT_FALSE(isMutated(Results, AST.get())); 470 471 AST = 472 buildASTFromCode("template <class T> struct identity { using type = T; };" 473 "template <class T, class U = const T&>" 474 "void g(typename identity<U>::type);" 475 "void f() { int x; g<int>(x); }"); 476 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 477 EXPECT_FALSE(isMutated(Results, AST.get())); 478 479 AST = buildASTFromCode( 480 "struct A {}; A operator+(const A&, int); void f() { A x; x + 1; }"); 481 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 482 EXPECT_FALSE(isMutated(Results, AST.get())); 483 484 AST = buildASTFromCode( 485 "void f() { struct A { A(const int&); }; int x; A y(x); }"); 486 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 487 EXPECT_FALSE(isMutated(Results, AST.get())); 488 489 AST = buildASTFromCode( 490 "void f() { struct A { A(); A(const A&); }; A x; A y(x); }"); 491 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 492 EXPECT_FALSE(isMutated(Results, AST.get())); 493 } 494 495 TEST(ExprMutationAnalyzerTest, ByNonConstRRefArgument) { 496 auto AST = buildASTFromCode( 497 "void g(int&&); void f() { int x; g(static_cast<int &&>(x)); }"); 498 auto Results = 499 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 500 EXPECT_THAT(mutatedBy(Results, AST.get()), 501 ElementsAre("g(static_cast<int &&>(x))")); 502 503 AST = buildASTFromCode("struct A {}; A operator+(A&&, int);" 504 "void f() { A x; static_cast<A &&>(x) + 1; }"); 505 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 506 EXPECT_THAT(mutatedBy(Results, AST.get()), 507 ElementsAre("static_cast<A &&>(x) + 1")); 508 509 AST = buildASTFromCode("void f() { struct A { A(int&&); }; " 510 "int x; A y(static_cast<int &&>(x)); }"); 511 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 512 EXPECT_THAT(mutatedBy(Results, AST.get()), 513 ElementsAre("static_cast<int &&>(x)")); 514 515 AST = buildASTFromCode("void f() { struct A { A(); A(A&&); }; " 516 "A x; A y(static_cast<A &&>(x)); }"); 517 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 518 EXPECT_THAT(mutatedBy(Results, AST.get()), 519 ElementsAre("static_cast<A &&>(x)")); 520 } 521 522 TEST(ExprMutationAnalyzerTest, ByConstRRefArgument) { 523 auto AST = buildASTFromCode( 524 "void g(const int&&); void f() { int x; g(static_cast<int&&>(x)); }"); 525 auto Results = 526 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 527 EXPECT_THAT(mutatedBy(Results, AST.get()), 528 ElementsAre("static_cast<int &&>(x)")); 529 530 AST = buildASTFromCode("struct A {}; A operator+(const A&&, int);" 531 "void f() { A x; static_cast<A&&>(x) + 1; }"); 532 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 533 EXPECT_THAT(mutatedBy(Results, AST.get()), 534 ElementsAre("static_cast<A &&>(x)")); 535 536 AST = buildASTFromCode("void f() { struct A { A(const int&&); }; " 537 "int x; A y(static_cast<int&&>(x)); }"); 538 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 539 EXPECT_THAT(mutatedBy(Results, AST.get()), 540 ElementsAre("static_cast<int &&>(x)")); 541 542 AST = buildASTFromCode("void f() { struct A { A(); A(const A&&); }; " 543 "A x; A y(static_cast<A&&>(x)); }"); 544 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 545 EXPECT_THAT(mutatedBy(Results, AST.get()), 546 ElementsAre("static_cast<A &&>(x)")); 547 } 548 549 // section: explicit std::move and std::forward testing 550 551 TEST(ExprMutationAnalyzerTest, Move) { 552 auto AST = buildASTFromCode(StdRemoveReference + StdMove + 553 "void f() { struct A {}; A x; std::move(x); }"); 554 auto Results = 555 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 556 EXPECT_FALSE(isMutated(Results, AST.get())); 557 558 AST = buildASTFromCode(StdRemoveReference + StdMove + 559 "void f() { struct A {}; A x, y; std::move(x) = y; }"); 560 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 561 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x) = y")); 562 563 AST = buildASTFromCode(StdRemoveReference + StdMove + 564 "void f() { int x, y; y = std::move(x); }"); 565 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 566 EXPECT_FALSE(isMutated(Results, AST.get())); 567 568 AST = 569 buildASTFromCode(StdRemoveReference + StdMove + 570 "struct S { S(); S(const S&); S& operator=(const S&); };" 571 "void f() { S x, y; y = std::move(x); }"); 572 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 573 EXPECT_FALSE(isMutated(Results, AST.get())); 574 575 AST = buildASTFromCode(StdRemoveReference + StdMove + 576 "struct S { S(); S(S&&); S& operator=(S&&); };" 577 "void f() { S x, y; y = std::move(x); }"); 578 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 579 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 580 581 AST = buildASTFromCode(StdRemoveReference + StdMove + 582 "struct S { S(); S(const S&); S(S&&);" 583 "S& operator=(const S&); S& operator=(S&&); };" 584 "void f() { S x, y; y = std::move(x); }"); 585 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 586 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 587 588 AST = buildASTFromCode(StdRemoveReference + StdMove + 589 "struct S { S(); S(const S&); S(S&&);" 590 "S& operator=(const S&); S& operator=(S&&); };" 591 "void f() { const S x; S y; y = std::move(x); }"); 592 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 593 EXPECT_FALSE(isMutated(Results, AST.get())); 594 595 AST = buildASTFromCode(StdRemoveReference + StdMove + 596 "struct S { S(); S& operator=(S); };" 597 "void f() { S x, y; y = std::move(x); }"); 598 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 599 EXPECT_FALSE(isMutated(Results, AST.get())); 600 601 AST = buildASTFromCode(StdRemoveReference + StdMove + 602 "struct S{}; void f() { S x, y; y = std::move(x); }"); 603 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 604 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 605 606 AST = buildASTFromCode( 607 StdRemoveReference + StdMove + 608 "struct S{}; void f() { const S x; S y; y = std::move(x); }"); 609 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 610 EXPECT_FALSE(isMutated(Results, AST.get())); 611 } 612 613 TEST(ExprMutationAnalyzerTest, Forward) { 614 auto AST = 615 buildASTFromCode(StdRemoveReference + StdForward + 616 "void f() { struct A {}; A x; std::forward<A &>(x); }"); 617 auto Results = 618 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 619 EXPECT_FALSE(isMutated(Results, AST.get())); 620 621 AST = buildASTFromCode( 622 StdRemoveReference + StdForward + 623 "void f() { struct A {}; A x, y; std::forward<A &>(x) = y; }"); 624 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 625 EXPECT_THAT(mutatedBy(Results, AST.get()), 626 ElementsAre("std::forward<A &>(x) = y")); 627 } 628 629 // section: template constellations that prohibit reasoning about modifications 630 // as it depends on instantiations. 631 632 TEST(ExprMutationAnalyzerTest, CallUnresolved) { 633 auto AST = 634 buildASTFromCodeWithArgs("template <class T> void f() { T x; g(x); }", 635 {"-fno-delayed-template-parsing"}); 636 auto Results = 637 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 638 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 639 640 AST = 641 buildASTFromCodeWithArgs("template <int N> void f() { char x[N]; g(x); }", 642 {"-fno-delayed-template-parsing"}); 643 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 644 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 645 646 AST = buildASTFromCodeWithArgs( 647 "template <class T> void f(T t) { int x; g(t, x); }", 648 {"-fno-delayed-template-parsing"}); 649 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 650 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(t, x)")); 651 652 AST = buildASTFromCodeWithArgs( 653 "template <class T> void f(T t) { int x; t.mf(x); }", 654 {"-fno-delayed-template-parsing"}); 655 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 656 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("t.mf(x)")); 657 658 AST = buildASTFromCodeWithArgs( 659 "template <class T> struct S;" 660 "template <class T> void f() { S<T> s; int x; s.mf(x); }", 661 {"-fno-delayed-template-parsing"}); 662 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 663 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)")); 664 665 AST = buildASTFromCodeWithArgs( 666 "struct S { template <class T> void mf(); };" 667 "template <class T> void f(S s) { int x; s.mf<T>(x); }", 668 {"-fno-delayed-template-parsing"}); 669 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 670 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf<T>(x)")); 671 672 AST = buildASTFromCodeWithArgs("template <class F>" 673 "void g(F f) { int x; f(x); } ", 674 {"-fno-delayed-template-parsing"}); 675 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 676 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f(x)")); 677 678 AST = buildASTFromCodeWithArgs( 679 "template <class T> void f() { int x; (void)T(x); }", 680 {"-fno-delayed-template-parsing"}); 681 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 682 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("T(x)")); 683 } 684 685 // section: return values 686 687 TEST(ExprMutationAnalyzerTest, ReturnAsValue) { 688 auto AST = buildASTFromCode("int f() { int x; return x; }"); 689 auto Results = 690 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 691 EXPECT_FALSE(isMutated(Results, AST.get())); 692 693 AST = buildASTFromCode("int* f() { int* x; return x; }"); 694 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 695 EXPECT_FALSE(isMutated(Results, AST.get())); 696 697 AST = buildASTFromCode("typedef int* IntPtr;" 698 "IntPtr f() { int* x; return x; }"); 699 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 700 EXPECT_FALSE(isMutated(Results, AST.get())); 701 } 702 703 TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) { 704 const auto AST = buildASTFromCode("int& f() { int x; return x; }"); 705 const auto Results = 706 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 707 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;")); 708 } 709 710 TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) { 711 const auto AST = buildASTFromCode("const int& f() { int x; return x; }"); 712 const auto Results = 713 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 714 EXPECT_FALSE(isMutated(Results, AST.get())); 715 } 716 717 TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRRef) { 718 const auto AST = 719 buildASTFromCode("int&& f() { int x; return static_cast<int &&>(x); }"); 720 const auto Results = 721 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 722 EXPECT_THAT(mutatedBy(Results, AST.get()), 723 ElementsAre("static_cast<int &&>(x)")); 724 } 725 726 TEST(ExprMutationAnalyzerTest, ReturnAsConstRRef) { 727 const auto AST = buildASTFromCode( 728 "const int&& f() { int x; return static_cast<int&&>(x); }"); 729 const auto Results = 730 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 731 EXPECT_THAT(mutatedBy(Results, AST.get()), 732 ElementsAre("static_cast<int &&>(x)")); 733 } 734 735 // section: taking the address of a variable and pointers 736 737 TEST(ExprMutationAnalyzerTest, TakeAddress) { 738 const auto AST = buildASTFromCode("void g(int*); void f() { int x; g(&x); }"); 739 const auto Results = 740 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 741 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x")); 742 } 743 744 TEST(ExprMutationAnalyzerTest, ArrayToPointerDecay) { 745 const auto AST = 746 buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }"); 747 const auto Results = 748 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 749 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 750 } 751 752 TEST(ExprMutationAnalyzerTest, TemplateWithArrayToPointerDecay) { 753 const auto AST = buildASTFromCodeWithArgs( 754 "template <typename T> struct S { static constexpr int v = 8; };" 755 "template <> struct S<int> { static constexpr int v = 4; };" 756 "void g(char*);" 757 "template <typename T> void f() { char x[S<T>::v]; g(x); }" 758 "template <> void f<int>() { char y[S<int>::v]; g(y); }", 759 {"-fno-delayed-template-parsing"}); 760 const auto ResultsX = 761 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 762 EXPECT_THAT(mutatedBy(ResultsX, AST.get()), ElementsAre("g(x)")); 763 const auto ResultsY = 764 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 765 EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y")); 766 } 767 768 // section: special case: all created references are non-mutating themself 769 // and therefore all become 'const'/the value is not modified! 770 771 TEST(ExprMutationAnalyzerTest, FollowRefModified) { 772 auto AST = buildASTFromCode( 773 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " 774 "int& r3 = r2; r3 = 10; }"); 775 auto Results = 776 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 777 EXPECT_THAT(mutatedBy(Results, AST.get()), 778 ElementsAre("r0", "r1", "r2", "r3", "r3 = 10")); 779 780 AST = buildASTFromCode("typedef int& IntRefX;" 781 "using IntRefY = int&;" 782 "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;" 783 "decltype((x)) r2 = r1; r2 = 10; }"); 784 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 785 EXPECT_THAT(mutatedBy(Results, AST.get()), 786 ElementsAre("r0", "r1", "r2", "r2 = 10")); 787 } 788 789 TEST(ExprMutationAnalyzerTest, FollowRefNotModified) { 790 auto AST = buildASTFromCode( 791 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " 792 "int& r3 = r2; int& r4 = r3; int& r5 = r4;}"); 793 auto Results = 794 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 795 EXPECT_FALSE(isMutated(Results, AST.get())); 796 797 AST = buildASTFromCode("void f() { int x; int& r0 = x; const int& r1 = r0;}"); 798 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 799 EXPECT_FALSE(isMutated(Results, AST.get())); 800 801 AST = buildASTFromCode("typedef const int& CIntRefX;" 802 "using CIntRefY = const int&;" 803 "void f() { int x; int& r0 = x; CIntRefX r1 = r0;" 804 "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}"); 805 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 806 EXPECT_FALSE(isMutated(Results, AST.get())); 807 } 808 809 TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) { 810 const auto AST = buildASTFromCode( 811 "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }"); 812 const auto Results = 813 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 814 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10")); 815 } 816 817 TEST(ExprMutationAnalyzerTest, FollowConditionalRefNotModified) { 818 const auto AST = 819 buildASTFromCode("void f() { int x, y; bool b; int& r = b ? x : y; }"); 820 const auto Results = 821 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 822 EXPECT_FALSE(isMutated(Results, AST.get())); 823 } 824 825 TEST(ExprMutationAnalyzerTest, FollowFuncArgModified) { 826 auto AST = buildASTFromCode("template <class T> void g(T&& t) { t = 10; }" 827 "void f() { int x; g(x); }"); 828 auto Results = 829 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 830 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 831 832 AST = buildASTFromCode( 833 "void h(int&);" 834 "template <class... Args> void g(Args&&... args) { h(args...); }" 835 "void f() { int x; g(x); }"); 836 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 837 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 838 839 AST = buildASTFromCode( 840 "void h(int&, int);" 841 "template <class... Args> void g(Args&&... args) { h(args...); }" 842 "void f() { int x, y; g(x, y); }"); 843 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 844 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x, y)")); 845 Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 846 EXPECT_FALSE(isMutated(Results, AST.get())); 847 848 AST = buildASTFromCode( 849 "void h(int, int&);" 850 "template <class... Args> void g(Args&&... args) { h(args...); }" 851 "void f() { int x, y; g(y, x); }"); 852 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 853 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(y, x)")); 854 Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 855 EXPECT_FALSE(isMutated(Results, AST.get())); 856 857 AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t = 10; } };" 858 "void f() { int x; S s(x); }"); 859 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 860 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 861 862 AST = buildASTFromCode( 863 "struct S { template <class T> S(T&& t) : m(++t) { } int m; };" 864 "void f() { int x; S s(x); }"); 865 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 866 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 867 868 AST = buildASTFromCode("template <class U> struct S {" 869 "template <class T> S(T&& t) : m(++t) { } U m; };" 870 "void f() { int x; S<int> s(x); }"); 871 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 872 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 873 874 AST = buildASTFromCode(StdRemoveReference + StdForward + 875 "template <class... Args> void u(Args&...);" 876 "template <class... Args> void h(Args&&... args)" 877 "{ u(std::forward<Args>(args)...); }" 878 "template <class... Args> void g(Args&&... args)" 879 "{ h(std::forward<Args>(args)...); }" 880 "void f() { int x; g(x); }"); 881 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 882 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 883 } 884 885 TEST(ExprMutationAnalyzerTest, FollowFuncArgNotModified) { 886 auto AST = buildASTFromCode("template <class T> void g(T&&) {}" 887 "void f() { int x; g(x); }"); 888 auto Results = 889 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 890 EXPECT_FALSE(isMutated(Results, AST.get())); 891 892 AST = buildASTFromCode("template <class T> void g(T&& t) { t; }" 893 "void f() { int x; g(x); }"); 894 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 895 EXPECT_FALSE(isMutated(Results, AST.get())); 896 897 AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}" 898 "void f() { int x; g(x); }"); 899 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 900 EXPECT_FALSE(isMutated(Results, AST.get())); 901 902 AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}" 903 "void f() { int y, x; g(y, x); }"); 904 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 905 EXPECT_FALSE(isMutated(Results, AST.get())); 906 907 AST = buildASTFromCode( 908 "void h(int, int&);" 909 "template <class... Args> void g(Args&&... args) { h(args...); }" 910 "void f() { int x, y; g(x, y); }"); 911 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 912 EXPECT_FALSE(isMutated(Results, AST.get())); 913 914 AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t; } };" 915 "void f() { int x; S s(x); }"); 916 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 917 EXPECT_FALSE(isMutated(Results, AST.get())); 918 919 AST = buildASTFromCode( 920 "struct S { template <class T> S(T&& t) : m(t) { } int m; };" 921 "void f() { int x; S s(x); }"); 922 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 923 EXPECT_FALSE(isMutated(Results, AST.get())); 924 925 AST = buildASTFromCode("template <class U> struct S {" 926 "template <class T> S(T&& t) : m(t) { } U m; };" 927 "void f() { int x; S<int> s(x); }"); 928 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 929 EXPECT_FALSE(isMutated(Results, AST.get())); 930 931 AST = buildASTFromCode(StdRemoveReference + StdForward + 932 "template <class... Args> void u(Args...);" 933 "template <class... Args> void h(Args&&... args)" 934 "{ u(std::forward<Args>(args)...); }" 935 "template <class... Args> void g(Args&&... args)" 936 "{ h(std::forward<Args>(args)...); }" 937 "void f() { int x; g(x); }"); 938 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 939 EXPECT_FALSE(isMutated(Results, AST.get())); 940 } 941 942 // section: builtin arrays 943 944 TEST(ExprMutationAnalyzerTest, ArrayElementModified) { 945 const auto AST = buildASTFromCode("void f() { int x[2]; x[0] = 10; }"); 946 const auto Results = 947 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 948 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10")); 949 } 950 951 TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) { 952 const auto AST = buildASTFromCode("void f() { int x[2]; x[0]; }"); 953 const auto Results = 954 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 955 EXPECT_FALSE(isMutated(Results, AST.get())); 956 } 957 958 // section: member modifications 959 960 TEST(ExprMutationAnalyzerTest, NestedMemberModified) { 961 auto AST = 962 buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " 963 "struct C { B vb; }; C x; x.vb.va.vi = 10; }"); 964 auto Results = 965 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 966 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10")); 967 968 AST = buildASTFromCodeWithArgs( 969 "template <class T> void f() { T x; x.y.z = 10; }", 970 {"-fno-delayed-template-parsing"}); 971 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 972 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); 973 974 AST = buildASTFromCodeWithArgs( 975 "template <class T> struct S;" 976 "template <class T> void f() { S<T> x; x.y.z = 10; }", 977 {"-fno-delayed-template-parsing"}); 978 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 979 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); 980 } 981 982 TEST(ExprMutationAnalyzerTest, NestedMemberNotModified) { 983 auto AST = 984 buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " 985 "struct C { B vb; }; C x; x.vb.va.vi; }"); 986 auto Results = 987 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 988 EXPECT_FALSE(isMutated(Results, AST.get())); 989 990 AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.y.z; }", 991 {"-fno-delayed-template-parsing"}); 992 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 993 EXPECT_FALSE(isMutated(Results, AST.get())); 994 995 AST = 996 buildASTFromCodeWithArgs("template <class T> struct S;" 997 "template <class T> void f() { S<T> x; x.y.z; }", 998 {"-fno-delayed-template-parsing"}); 999 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1000 EXPECT_FALSE(isMutated(Results, AST.get())); 1001 } 1002 1003 // section: casts 1004 1005 TEST(ExprMutationAnalyzerTest, CastToValue) { 1006 const auto AST = 1007 buildASTFromCode("void f() { int x; static_cast<double>(x); }"); 1008 const auto Results = 1009 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1010 EXPECT_FALSE(isMutated(Results, AST.get())); 1011 } 1012 1013 TEST(ExprMutationAnalyzerTest, CastToRefModified) { 1014 auto AST = 1015 buildASTFromCode("void f() { int x; static_cast<int &>(x) = 10; }"); 1016 auto Results = 1017 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1018 EXPECT_THAT(mutatedBy(Results, AST.get()), 1019 ElementsAre("static_cast<int &>(x)")); 1020 1021 AST = buildASTFromCode("typedef int& IntRef;" 1022 "void f() { int x; static_cast<IntRef>(x) = 10; }"); 1023 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1024 EXPECT_THAT(mutatedBy(Results, AST.get()), 1025 ElementsAre("static_cast<IntRef>(x)")); 1026 } 1027 1028 TEST(ExprMutationAnalyzerTest, CastToRefNotModified) { 1029 const auto AST = 1030 buildASTFromCode("void f() { int x; static_cast<int&>(x); }"); 1031 const auto Results = 1032 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1033 EXPECT_THAT(mutatedBy(Results, AST.get()), 1034 ElementsAre("static_cast<int &>(x)")); 1035 } 1036 1037 TEST(ExprMutationAnalyzerTest, CastToConstRef) { 1038 auto AST = 1039 buildASTFromCode("void f() { int x; static_cast<const int&>(x); }"); 1040 auto Results = 1041 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1042 EXPECT_FALSE(isMutated(Results, AST.get())); 1043 1044 AST = buildASTFromCode("typedef const int& CIntRef;" 1045 "void f() { int x; static_cast<CIntRef>(x); }"); 1046 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1047 EXPECT_FALSE(isMutated(Results, AST.get())); 1048 } 1049 1050 // section: comma expressions 1051 1052 TEST(ExprMutationAnalyzerTest, CommaExprWithAnAssigment) { 1053 const auto AST = buildASTFromCodeWithArgs( 1054 "void f() { int x; int y; (x, y) = 5; }", {"-Wno-unused-value"}); 1055 const auto Results = 1056 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 1057 EXPECT_TRUE(isMutated(Results, AST.get())); 1058 } 1059 1060 TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) { 1061 const auto AST = buildASTFromCodeWithArgs( 1062 "void f() { int x; int y; (x, y)++; }", {"-Wno-unused-value"}); 1063 const auto Results = 1064 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 1065 EXPECT_TRUE(isMutated(Results, AST.get())); 1066 } 1067 1068 TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) { 1069 const auto AST = buildASTFromCodeWithArgs( 1070 "class A { public: int mem; void f() { mem ++; } };" 1071 "void fn() { A o1, o2; (o1, o2).f(); }", 1072 {"-Wno-unused-value"}); 1073 const auto Results = 1074 match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext()); 1075 EXPECT_TRUE(isMutated(Results, AST.get())); 1076 } 1077 1078 TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) { 1079 const auto AST = buildASTFromCodeWithArgs( 1080 "class A { public: int mem; void f() const { } };" 1081 "void fn() { A o1, o2; (o1, o2).f(); }", 1082 {"-Wno-unused-value"}); 1083 const auto Results = 1084 match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext()); 1085 EXPECT_FALSE(isMutated(Results, AST.get())); 1086 } 1087 1088 TEST(ExprMutationAnalyzerTest, CommaExprWithCallExpr) { 1089 const auto AST = 1090 buildASTFromCodeWithArgs("class A { public: int mem; void f(A &O1) {} };" 1091 "void fn() { A o1, o2; o2.f((o2, o1)); }", 1092 {"-Wno-unused-value"}); 1093 const auto Results = 1094 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 1095 EXPECT_TRUE(isMutated(Results, AST.get())); 1096 } 1097 1098 TEST(ExprMutationAnalyzerTest, CommaExprWithCallUnresolved) { 1099 auto AST = buildASTFromCodeWithArgs( 1100 "template <class T> struct S;" 1101 "template <class T> void f() { S<T> s; int x, y; s.mf((y, x)); }", 1102 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1103 auto Results = 1104 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1105 EXPECT_TRUE(isMutated(Results, AST.get())); 1106 1107 AST = buildASTFromCodeWithArgs( 1108 "template <class T> void f(T t) { int x, y; g(t, (y, x)); }", 1109 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1110 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1111 EXPECT_TRUE(isMutated(Results, AST.get())); 1112 } 1113 1114 TEST(ExprMutationAnalyzerTest, CommaExprParmRef) { 1115 const auto AST = 1116 buildASTFromCodeWithArgs("class A { public: int mem;};" 1117 "extern void fn(A &o1);" 1118 "void fn2 () { A o1, o2; fn((o2, o1)); } ", 1119 {"-Wno-unused-value"}); 1120 const auto Results = 1121 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 1122 EXPECT_TRUE(isMutated(Results, AST.get())); 1123 } 1124 1125 TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) { 1126 const auto AST = buildASTFromCodeWithArgs("class A { public: int mem;};" 1127 "void fn () { A o1, o2;" 1128 "void *addr = &(o2, o1); } ", 1129 {"-Wno-unused-value"}); 1130 const auto Results = 1131 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 1132 EXPECT_TRUE(isMutated(Results, AST.get())); 1133 } 1134 1135 TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsValue) { 1136 auto AST = buildASTFromCodeWithArgs("int f() { int x, y; return (x, y); }", 1137 {"-Wno-unused-value"}); 1138 auto Results = 1139 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 1140 EXPECT_FALSE(isMutated(Results, AST.get())); 1141 } 1142 1143 TEST(ExprMutationAnalyzerTest, CommaEpxrAsReturnAsNonConstRef) { 1144 const auto AST = buildASTFromCodeWithArgs( 1145 "int& f() { int x, y; return (y, x); }", {"-Wno-unused-value"}); 1146 const auto Results = 1147 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1148 EXPECT_TRUE(isMutated(Results, AST.get())); 1149 } 1150 1151 TEST(ExprMutationAnalyzerTest, CommaExprAsArrayToPointerDecay) { 1152 const auto AST = 1153 buildASTFromCodeWithArgs("void g(int*); " 1154 "void f() { int x[2], y[2]; g((y, x)); }", 1155 {"-Wno-unused-value"}); 1156 const auto Results = 1157 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1158 EXPECT_TRUE(isMutated(Results, AST.get())); 1159 } 1160 1161 TEST(ExprMutationAnalyzerTest, CommaExprAsUniquePtr) { 1162 const std::string UniquePtrDef = "template <class T> struct UniquePtr {" 1163 " UniquePtr();" 1164 " UniquePtr(const UniquePtr&) = delete;" 1165 " T& operator*() const;" 1166 " T* operator->() const;" 1167 "};"; 1168 const auto AST = buildASTFromCodeWithArgs( 1169 UniquePtrDef + "template <class T> void f() " 1170 "{ UniquePtr<T> x; UniquePtr<T> y;" 1171 " (y, x)->mf(); }", 1172 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1173 const auto Results = 1174 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1175 EXPECT_TRUE(isMutated(Results, AST.get())); 1176 } 1177 1178 TEST(ExprMutationAnalyzerTest, CommaNestedConditional) { 1179 const std::string Code = "void f() { int x, y = 42;" 1180 " y, (true ? x : y) = 42; }"; 1181 const auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"}); 1182 const auto Results = 1183 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1184 EXPECT_THAT(mutatedBy(Results, AST.get()), 1185 ElementsAre("(true ? x : y) = 42")); 1186 } 1187 1188 // section: lambda captures 1189 1190 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) { 1191 const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }"); 1192 const auto Results = 1193 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1194 EXPECT_FALSE(isMutated(Results, AST.get())); 1195 } 1196 1197 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) { 1198 const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }"); 1199 const auto Results = 1200 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1201 EXPECT_FALSE(isMutated(Results, AST.get())); 1202 } 1203 1204 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) { 1205 const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }"); 1206 const auto Results = 1207 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1208 EXPECT_THAT(mutatedBy(Results, AST.get()), 1209 ElementsAre(ResultOf(removeSpace, "[&](){x=10;}"))); 1210 } 1211 1212 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) { 1213 const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }"); 1214 const auto Results = 1215 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1216 EXPECT_THAT(mutatedBy(Results, AST.get()), 1217 ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}"))); 1218 } 1219 1220 // section: range-for loops 1221 1222 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) { 1223 auto AST = 1224 buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }"); 1225 auto Results = 1226 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1227 EXPECT_THAT(mutatedBy(Results, AST.get()), 1228 ElementsAre("for (int &e : x)\n e = 10;")); 1229 1230 AST = buildASTFromCode("typedef int& IntRef;" 1231 "void f() { int x[2]; for (IntRef e : x) e = 10; }"); 1232 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1233 EXPECT_THAT(mutatedBy(Results, AST.get()), 1234 ElementsAre("for (IntRef e : x)\n e = 10;")); 1235 } 1236 1237 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModifiedByImplicitInit) { 1238 const auto AST = 1239 buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }"); 1240 const auto Results = 1241 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1242 EXPECT_TRUE(isMutated(Results, AST.get())); 1243 } 1244 1245 TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) { 1246 auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }"); 1247 auto Results = 1248 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1249 EXPECT_FALSE(isMutated(Results, AST.get())); 1250 1251 AST = 1252 buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }"); 1253 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1254 EXPECT_FALSE(isMutated(Results, AST.get())); 1255 1256 AST = buildASTFromCode( 1257 "typedef int* IntPtr;" 1258 "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }"); 1259 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1260 EXPECT_FALSE(isMutated(Results, AST.get())); 1261 } 1262 1263 TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) { 1264 auto AST = 1265 buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }"); 1266 auto Results = 1267 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1268 EXPECT_FALSE(isMutated(Results, AST.get())); 1269 1270 AST = buildASTFromCode("typedef const int& CIntRef;" 1271 "void f() { int x[2]; for (CIntRef e : x) e; }"); 1272 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1273 EXPECT_FALSE(isMutated(Results, AST.get())); 1274 } 1275 1276 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) { 1277 const auto AST = 1278 buildASTFromCode("struct V { int* begin(); int* end(); };" 1279 "void f() { V x; for (int& e : x) e = 10; }"); 1280 const auto Results = 1281 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1282 EXPECT_THAT(mutatedBy(Results, AST.get()), 1283 ElementsAre("for (int &e : x)\n e = 10;")); 1284 } 1285 1286 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) { 1287 const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };" 1288 "void f() { V x; for (int& e : x) e; }"); 1289 const auto Results = 1290 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1291 EXPECT_TRUE(isMutated(Results, AST.get())); 1292 } 1293 1294 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) { 1295 const auto AST = buildASTFromCode( 1296 "struct V { const int* begin() const; const int* end() const; };" 1297 "void f() { V x; for (int e : x) e; }"); 1298 const auto Results = 1299 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1300 EXPECT_FALSE(isMutated(Results, AST.get())); 1301 } 1302 1303 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) { 1304 const auto AST = buildASTFromCode( 1305 "struct V { const int* begin() const; const int* end() const; };" 1306 "void f() { V x; for (const int& e : x) e; }"); 1307 const auto Results = 1308 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1309 EXPECT_FALSE(isMutated(Results, AST.get())); 1310 } 1311 1312 // section: unevaluated expressions 1313 1314 TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) { 1315 auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }"); 1316 auto Results = 1317 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1318 EXPECT_FALSE(isMutated(Results, AST.get())); 1319 1320 AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }"); 1321 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1322 EXPECT_FALSE(isMutated(Results, AST.get())); 1323 1324 AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }"); 1325 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1326 EXPECT_FALSE(isMutated(Results, AST.get())); 1327 1328 AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }"); 1329 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1330 EXPECT_FALSE(isMutated(Results, AST.get())); 1331 1332 AST = buildASTFromCode("void f() { int x; alignof(x = 10); }"); 1333 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1334 EXPECT_FALSE(isMutated(Results, AST.get())); 1335 1336 AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }"); 1337 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1338 EXPECT_FALSE(isMutated(Results, AST.get())); 1339 1340 AST = buildASTFromCodeWithArgs("namespace std { class type_info; }" 1341 "void f() { int x; typeid(x = 10); }", 1342 {"-frtti"}); 1343 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1344 EXPECT_FALSE(isMutated(Results, AST.get())); 1345 1346 AST = buildASTFromCode( 1347 "void f() { int x; _Generic(x = 10, int: 0, default: 1); }"); 1348 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1349 EXPECT_FALSE(isMutated(Results, AST.get())); 1350 } 1351 1352 TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) { 1353 auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }"); 1354 auto Results = 1355 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1356 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++")); 1357 1358 AST = buildASTFromCodeWithArgs( 1359 "namespace std { class type_info; }" 1360 "struct A { virtual ~A(); }; struct B : A {};" 1361 "struct X { A& f(); }; void f() { X x; typeid(x.f()); }", 1362 {"-frtti"}); 1363 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1364 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()")); 1365 } 1366 1367 // section: special case: smartpointers 1368 1369 TEST(ExprMutationAnalyzerTest, UniquePtr) { 1370 const std::string UniquePtrDef = 1371 "template <class T> struct UniquePtr {" 1372 " UniquePtr();" 1373 " UniquePtr(const UniquePtr&) = delete;" 1374 " UniquePtr(UniquePtr&&);" 1375 " UniquePtr& operator=(const UniquePtr&) = delete;" 1376 " UniquePtr& operator=(UniquePtr&&);" 1377 " T& operator*() const;" 1378 " T* operator->() const;" 1379 "};"; 1380 1381 auto AST = buildASTFromCode(UniquePtrDef + 1382 "void f() { UniquePtr<int> x; *x = 10; }"); 1383 auto Results = 1384 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1385 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10")); 1386 1387 AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr<int> x; *x; }"); 1388 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1389 EXPECT_FALSE(isMutated(Results, AST.get())); 1390 1391 AST = buildASTFromCode(UniquePtrDef + 1392 "void f() { UniquePtr<const int> x; *x; }"); 1393 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1394 EXPECT_FALSE(isMutated(Results, AST.get())); 1395 1396 AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };" 1397 "void f() { UniquePtr<S> x; x->v; }"); 1398 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1399 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1400 1401 AST = buildASTFromCode(UniquePtrDef + 1402 "struct S { int v; };" 1403 "void f() { UniquePtr<const S> x; x->v; }"); 1404 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1405 EXPECT_FALSE(isMutated(Results, AST.get())); 1406 1407 AST = 1408 buildASTFromCode(UniquePtrDef + "struct S { void mf(); };" 1409 "void f() { UniquePtr<S> x; x->mf(); }"); 1410 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1411 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1412 1413 AST = buildASTFromCode(UniquePtrDef + 1414 "struct S { void mf() const; };" 1415 "void f() { UniquePtr<const S> x; x->mf(); }"); 1416 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1417 EXPECT_FALSE(isMutated(Results, AST.get())); 1418 1419 AST = buildASTFromCodeWithArgs( 1420 UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }", 1421 {"-fno-delayed-template-parsing"}); 1422 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1423 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()")); 1424 } 1425 1426 // section: complex problems detected on real code 1427 1428 TEST(ExprMutationAnalyzerTest, UnevaluatedContext) { 1429 const std::string Example = 1430 "template <typename T>" 1431 "struct to_construct : T { to_construct(int &j) {} };" 1432 "template <typename T>" 1433 "void placement_new_in_unique_ptr() { int x = 0;" 1434 " new to_construct<T>(x);" 1435 "}"; 1436 auto AST = 1437 buildASTFromCodeWithArgs(Example, {"-fno-delayed-template-parsing"}); 1438 auto Results = 1439 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1440 EXPECT_TRUE(isMutated(Results, AST.get())); 1441 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(x)")); 1442 } 1443 1444 TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) { 1445 const std::string Reproducer = 1446 "namespace std {" 1447 "template <class T> T &forward(T &A) { return static_cast<T&&>(A); }" 1448 "template <class T> struct __bind {" 1449 " T f;" 1450 " template <class V> __bind(T v, V &&) : f(forward(v)) {}" 1451 "};" 1452 "}" 1453 "void f() {" 1454 " int x = 42;" 1455 " auto Lambda = [] {};" 1456 " std::__bind<decltype(Lambda)>(Lambda, x);" 1457 "}"; 1458 auto AST11 = buildASTFromCodeWithArgs(Reproducer, {"-std=c++11"}); 1459 auto Results11 = 1460 match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext()); 1461 EXPECT_FALSE(isMutated(Results11, AST11.get())); 1462 } 1463 } // namespace clang 1464