1 //===---------- ExprMutationAnalyzerTest.cpp ------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.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::IsEmpty; 24 using ::testing::ResultOf; 25 using ::testing::StartsWith; 26 using ::testing::Values; 27 28 namespace { 29 30 using ExprMatcher = internal::Matcher<Expr>; 31 using StmtMatcher = internal::Matcher<Stmt>; 32 33 std::unique_ptr<ASTUnit> 34 buildASTFromCodeWithArgs(const Twine &Code, 35 const std::vector<std::string> &Args) { 36 SmallString<1024> CodeStorage; 37 auto AST = 38 tooling::buildASTFromCodeWithArgs(Code.toStringRef(CodeStorage), Args); 39 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred()); 40 return AST; 41 } 42 43 std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code) { 44 return buildASTFromCodeWithArgs(Code, {}); 45 } 46 47 ExprMatcher declRefTo(StringRef Name) { 48 return declRefExpr(to(namedDecl(hasName(Name)))); 49 } 50 51 StmtMatcher withEnclosingCompound(ExprMatcher Matcher) { 52 return expr(Matcher, hasAncestor(compoundStmt().bind("stmt"))).bind("expr"); 53 } 54 55 bool isMutated(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) { 56 const auto *const S = selectFirst<Stmt>("stmt", Results); 57 const auto *const E = selectFirst<Expr>("expr", Results); 58 return ExprMutationAnalyzer(*S, AST->getASTContext()).isMutated(E); 59 } 60 61 SmallVector<std::string, 1> 62 mutatedBy(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) { 63 const auto *const S = selectFirst<Stmt>("stmt", Results); 64 SmallVector<std::string, 1> Chain; 65 ExprMutationAnalyzer Analyzer(*S, AST->getASTContext()); 66 for (const auto *E = selectFirst<Expr>("expr", Results); E != nullptr;) { 67 const Stmt *By = Analyzer.findMutation(E); 68 std::string buffer; 69 llvm::raw_string_ostream stream(buffer); 70 By->printPretty(stream, nullptr, AST->getASTContext().getPrintingPolicy()); 71 Chain.push_back(StringRef(stream.str()).trim().str()); 72 E = dyn_cast<DeclRefExpr>(By); 73 } 74 return Chain; 75 } 76 77 std::string removeSpace(std::string s) { 78 s.erase(std::remove_if(s.begin(), s.end(), 79 [](char c) { return std::isspace(c); }), 80 s.end()); 81 return s; 82 } 83 84 const std::string StdRemoveReference = 85 "namespace std {" 86 "template<class T> struct remove_reference { typedef T type; };" 87 "template<class T> struct remove_reference<T&> { typedef T type; };" 88 "template<class T> struct remove_reference<T&&> { typedef T type; }; }"; 89 90 const std::string StdMove = 91 "namespace std {" 92 "template<class T> typename remove_reference<T>::type&& " 93 "move(T&& t) noexcept {" 94 "return static_cast<typename remove_reference<T>::type&&>(t); } }"; 95 96 const std::string StdForward = 97 "namespace std {" 98 "template<class T> T&& " 99 "forward(typename remove_reference<T>::type& t) noexcept { return t; }" 100 "template<class T> T&& " 101 "forward(typename remove_reference<T>::type&& t) noexcept { return t; } }"; 102 103 } // namespace 104 105 TEST(ExprMutationAnalyzerTest, Trivial) { 106 const auto AST = buildASTFromCode("void f() { int x; x; }"); 107 const auto Results = 108 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 109 EXPECT_FALSE(isMutated(Results, AST.get())); 110 } 111 112 class AssignmentTest : public ::testing::TestWithParam<std::string> {}; 113 114 TEST_P(AssignmentTest, AssignmentModifies) { 115 const std::string ModExpr = "x " + GetParam() + " 10"; 116 const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); 117 const auto Results = 118 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 119 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 120 } 121 122 INSTANTIATE_TEST_CASE_P(AllAssignmentOperators, AssignmentTest, 123 Values("=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", 124 "^=", "<<=", ">>="), ); 125 126 class IncDecTest : public ::testing::TestWithParam<std::string> {}; 127 128 TEST_P(IncDecTest, IncDecModifies) { 129 const std::string ModExpr = GetParam(); 130 const auto AST = buildASTFromCode("void f() { int x; " + ModExpr + "; }"); 131 const auto Results = 132 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 133 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr)); 134 } 135 136 INSTANTIATE_TEST_CASE_P(AllIncDecOperators, IncDecTest, 137 Values("++x", "--x", "x++", "x--"), ); 138 139 TEST(ExprMutationAnalyzerTest, NonConstMemberFunc) { 140 const auto AST = buildASTFromCode( 141 "void f() { struct Foo { void mf(); }; Foo x; x.mf(); }"); 142 const auto Results = 143 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 144 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); 145 } 146 147 TEST(ExprMutationAnalyzerTest, AssumedNonConstMemberFunc) { 148 auto AST = buildASTFromCodeWithArgs( 149 "struct X { template <class T> void mf(); };" 150 "template <class T> void f() { X x; x.mf<T>(); }", 151 {"-fno-delayed-template-parsing"}); 152 auto Results = 153 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 154 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf<T>()")); 155 156 AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.mf(); }", 157 {"-fno-delayed-template-parsing"}); 158 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 159 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); 160 161 AST = buildASTFromCodeWithArgs( 162 "template <class T> struct X;" 163 "template <class T> void f() { X<T> x; x.mf(); }", 164 {"-fno-delayed-template-parsing"}); 165 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 166 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()")); 167 } 168 169 TEST(ExprMutationAnalyzerTest, ConstMemberFunc) { 170 const auto AST = buildASTFromCode( 171 "void f() { struct Foo { void mf() const; }; Foo x; x.mf(); }"); 172 const auto Results = 173 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 174 EXPECT_FALSE(isMutated(Results, AST.get())); 175 } 176 177 TEST(ExprMutationAnalyzerTest, NonConstOperator) { 178 const auto AST = buildASTFromCode( 179 "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }"); 180 const auto Results = 181 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 182 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10")); 183 } 184 185 TEST(ExprMutationAnalyzerTest, ConstOperator) { 186 const auto AST = buildASTFromCode( 187 "void f() { struct Foo { int operator()() const; }; Foo x; x(); }"); 188 const auto Results = 189 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 190 EXPECT_FALSE(isMutated(Results, AST.get())); 191 } 192 193 TEST(ExprMutationAnalyzerTest, ByValueArgument) { 194 auto AST = buildASTFromCode("void g(int); void f() { int x; g(x); }"); 195 auto Results = 196 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 197 EXPECT_FALSE(isMutated(Results, AST.get())); 198 199 AST = buildASTFromCode("void g(int*); void f() { int* x; g(x); }"); 200 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 201 EXPECT_FALSE(isMutated(Results, AST.get())); 202 203 AST = buildASTFromCode("typedef int* IntPtr;" 204 "void g(IntPtr); void f() { int* x; g(x); }"); 205 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 206 EXPECT_FALSE(isMutated(Results, AST.get())); 207 208 AST = buildASTFromCode( 209 "struct A {}; A operator+(A, int); void f() { A x; x + 1; }"); 210 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 211 EXPECT_FALSE(isMutated(Results, AST.get())); 212 213 AST = buildASTFromCode("void f() { struct A { A(int); }; int x; A y(x); }"); 214 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 215 EXPECT_FALSE(isMutated(Results, AST.get())); 216 217 AST = buildASTFromCode("struct A { A(); A& operator=(A); };" 218 "void f() { A x, y; y = x; }"); 219 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 220 EXPECT_FALSE(isMutated(Results, AST.get())); 221 222 AST = buildASTFromCode( 223 "template <int> struct A { A(); A(const A&); static void mf(A) {} };" 224 "void f() { A<0> x; A<0>::mf(x); }"); 225 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 226 EXPECT_FALSE(isMutated(Results, AST.get())); 227 } 228 229 TEST(ExprMutationAnalyzerTest, ByConstValueArgument) { 230 auto AST = buildASTFromCode("void g(const int); void f() { int x; g(x); }"); 231 auto Results = 232 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 233 EXPECT_FALSE(isMutated(Results, AST.get())); 234 235 AST = buildASTFromCode("void g(int* const); void f() { int* x; g(x); }"); 236 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 237 EXPECT_FALSE(isMutated(Results, AST.get())); 238 239 AST = buildASTFromCode("typedef int* const CIntPtr;" 240 "void g(CIntPtr); void f() { int* x; g(x); }"); 241 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 242 EXPECT_FALSE(isMutated(Results, AST.get())); 243 244 AST = buildASTFromCode( 245 "struct A {}; A operator+(const A, int); void f() { A x; x + 1; }"); 246 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 247 EXPECT_FALSE(isMutated(Results, AST.get())); 248 249 AST = buildASTFromCode( 250 "void f() { struct A { A(const int); }; int x; A y(x); }"); 251 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 252 EXPECT_FALSE(isMutated(Results, AST.get())); 253 254 AST = buildASTFromCode("template <int> struct A { A(); A(const A&);" 255 "static void mf(const A&) {} };" 256 "void f() { A<0> x; A<0>::mf(x); }"); 257 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 258 EXPECT_FALSE(isMutated(Results, AST.get())); 259 } 260 261 TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) { 262 auto AST = buildASTFromCode("void g(int&); void f() { int x; g(x); }"); 263 auto Results = 264 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 265 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 266 267 AST = buildASTFromCode("typedef int& IntRef;" 268 "void g(IntRef); void f() { int x; g(x); }"); 269 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 270 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 271 272 AST = buildASTFromCode("template <class T> using TRef = T&;" 273 "void g(TRef<int>); void f() { int x; g(x); }"); 274 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 275 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 276 277 AST = buildASTFromCode( 278 "template <class T> struct identity { using type = T; };" 279 "template <class T, class U = T&> void g(typename identity<U>::type);" 280 "void f() { int x; g<int>(x); }"); 281 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 282 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g<int>(x)")); 283 284 AST = buildASTFromCode("typedef int* IntPtr;" 285 "void g(IntPtr&); void f() { int* x; g(x); }"); 286 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 287 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 288 289 AST = buildASTFromCode("typedef int* IntPtr; typedef IntPtr& IntPtrRef;" 290 "void g(IntPtrRef); void f() { int* x; g(x); }"); 291 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 292 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 293 294 AST = buildASTFromCode( 295 "struct A {}; A operator+(A&, int); void f() { A x; x + 1; }"); 296 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 297 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1")); 298 299 AST = buildASTFromCode("void f() { struct A { A(int&); }; int x; A y(x); }"); 300 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 301 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 302 303 AST = buildASTFromCode("void f() { struct A { A(); A(A&); }; A x; A y(x); }"); 304 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 305 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 306 307 AST = buildASTFromCode( 308 "template <int> struct A { A(); A(const A&); static void mf(A&) {} };" 309 "void f() { A<0> x; A<0>::mf(x); }"); 310 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 311 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("A<0>::mf(x)")); 312 } 313 314 TEST(ExprMutationAnalyzerTest, ByConstRefArgument) { 315 auto AST = buildASTFromCode("void g(const int&); void f() { int x; g(x); }"); 316 auto Results = 317 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 318 EXPECT_FALSE(isMutated(Results, AST.get())); 319 320 AST = buildASTFromCode("typedef const int& CIntRef;" 321 "void g(CIntRef); void f() { int x; g(x); }"); 322 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 323 EXPECT_FALSE(isMutated(Results, AST.get())); 324 325 AST = buildASTFromCode("template <class T> using CTRef = const T&;" 326 "void g(CTRef<int>); void f() { int x; g(x); }"); 327 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 328 EXPECT_FALSE(isMutated(Results, AST.get())); 329 330 AST = 331 buildASTFromCode("template <class T> struct identity { using type = T; };" 332 "template <class T, class U = const T&>" 333 "void g(typename identity<U>::type);" 334 "void f() { int x; g<int>(x); }"); 335 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 336 EXPECT_FALSE(isMutated(Results, AST.get())); 337 338 AST = buildASTFromCode( 339 "struct A {}; A operator+(const A&, int); void f() { A x; x + 1; }"); 340 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 341 EXPECT_FALSE(isMutated(Results, AST.get())); 342 343 AST = buildASTFromCode( 344 "void f() { struct A { A(const int&); }; int x; A y(x); }"); 345 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 346 EXPECT_FALSE(isMutated(Results, AST.get())); 347 348 AST = buildASTFromCode( 349 "void f() { struct A { A(); A(const A&); }; A x; A y(x); }"); 350 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 351 EXPECT_FALSE(isMutated(Results, AST.get())); 352 } 353 354 TEST(ExprMutationAnalyzerTest, ByNonConstRRefArgument) { 355 auto AST = buildASTFromCode( 356 "void g(int&&); void f() { int x; g(static_cast<int &&>(x)); }"); 357 auto Results = 358 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 359 EXPECT_THAT(mutatedBy(Results, AST.get()), 360 ElementsAre("g(static_cast<int &&>(x))")); 361 362 AST = buildASTFromCode("struct A {}; A operator+(A&&, int);" 363 "void f() { A x; static_cast<A &&>(x) + 1; }"); 364 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 365 EXPECT_THAT(mutatedBy(Results, AST.get()), 366 ElementsAre("static_cast<A &&>(x) + 1")); 367 368 AST = buildASTFromCode("void f() { struct A { A(int&&); }; " 369 "int x; A y(static_cast<int &&>(x)); }"); 370 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 371 EXPECT_THAT(mutatedBy(Results, AST.get()), 372 ElementsAre("static_cast<int &&>(x)")); 373 374 AST = buildASTFromCode("void f() { struct A { A(); A(A&&); }; " 375 "A x; A y(static_cast<A &&>(x)); }"); 376 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 377 EXPECT_THAT(mutatedBy(Results, AST.get()), 378 ElementsAre("static_cast<A &&>(x)")); 379 } 380 381 TEST(ExprMutationAnalyzerTest, ByConstRRefArgument) { 382 auto AST = buildASTFromCode( 383 "void g(const int&&); void f() { int x; g(static_cast<int&&>(x)); }"); 384 auto Results = 385 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 386 EXPECT_FALSE(isMutated(Results, AST.get())); 387 388 AST = buildASTFromCode("struct A {}; A operator+(const A&&, int);" 389 "void f() { A x; static_cast<A&&>(x) + 1; }"); 390 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 391 EXPECT_FALSE(isMutated(Results, AST.get())); 392 393 AST = buildASTFromCode("void f() { struct A { A(const int&&); }; " 394 "int x; A y(static_cast<int&&>(x)); }"); 395 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 396 EXPECT_FALSE(isMutated(Results, AST.get())); 397 398 AST = buildASTFromCode("void f() { struct A { A(); A(const A&&); }; " 399 "A x; A y(static_cast<A&&>(x)); }"); 400 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 401 EXPECT_FALSE(isMutated(Results, AST.get())); 402 } 403 404 TEST(ExprMutationAnalyzerTest, Move) { 405 auto AST = buildASTFromCode(StdRemoveReference + StdMove + 406 "void f() { struct A {}; A x; std::move(x); }"); 407 auto Results = 408 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 409 EXPECT_FALSE(isMutated(Results, AST.get())); 410 411 AST = buildASTFromCode(StdRemoveReference + StdMove + 412 "void f() { struct A {}; A x, y; std::move(x) = y; }"); 413 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 414 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x) = y")); 415 416 AST = buildASTFromCode(StdRemoveReference + StdMove + 417 "void f() { int x, y; y = std::move(x); }"); 418 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 419 EXPECT_FALSE(isMutated(Results, AST.get())); 420 421 AST = 422 buildASTFromCode(StdRemoveReference + StdMove + 423 "struct S { S(); S(const S&); S& operator=(const S&); };" 424 "void f() { S x, y; y = std::move(x); }"); 425 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 426 EXPECT_FALSE(isMutated(Results, AST.get())); 427 428 AST = buildASTFromCode(StdRemoveReference + StdMove + 429 "struct S { S(); S(S&&); S& operator=(S&&); };" 430 "void f() { S x, y; y = std::move(x); }"); 431 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 432 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 433 434 AST = buildASTFromCode(StdRemoveReference + StdMove + 435 "struct S { S(); S(const S&); S(S&&);" 436 "S& operator=(const S&); S& operator=(S&&); };" 437 "void f() { S x, y; y = std::move(x); }"); 438 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 439 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 440 441 AST = buildASTFromCode(StdRemoveReference + StdMove + 442 "struct S { S(); S(const S&); S(S&&);" 443 "S& operator=(const S&); S& operator=(S&&); };" 444 "void f() { const S x; S y; y = std::move(x); }"); 445 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 446 EXPECT_FALSE(isMutated(Results, AST.get())); 447 448 AST = buildASTFromCode(StdRemoveReference + StdMove + 449 "struct S { S(); S& operator=(S); };" 450 "void f() { S x, y; y = std::move(x); }"); 451 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 452 EXPECT_FALSE(isMutated(Results, AST.get())); 453 454 AST = buildASTFromCode(StdRemoveReference + StdMove + 455 "struct S{}; void f() { S x, y; y = std::move(x); }"); 456 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 457 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("y = std::move(x)")); 458 459 AST = buildASTFromCode( 460 StdRemoveReference + StdMove + 461 "struct S{}; void f() { const S x; S y; y = std::move(x); }"); 462 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 463 EXPECT_FALSE(isMutated(Results, AST.get())); 464 } 465 466 TEST(ExprMutationAnalyzerTest, Forward) { 467 auto AST = 468 buildASTFromCode(StdRemoveReference + StdForward + 469 "void f() { struct A {}; A x; std::forward<A &>(x); }"); 470 auto Results = 471 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 472 EXPECT_FALSE(isMutated(Results, AST.get())); 473 474 AST = buildASTFromCode( 475 StdRemoveReference + StdForward + 476 "void f() { struct A {}; A x, y; std::forward<A &>(x) = y; }"); 477 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 478 EXPECT_THAT(mutatedBy(Results, AST.get()), 479 ElementsAre("std::forward<A &>(x) = y")); 480 } 481 482 TEST(ExprMutationAnalyzerTest, CallUnresolved) { 483 auto AST = 484 buildASTFromCodeWithArgs("template <class T> void f() { T x; g(x); }", 485 {"-fno-delayed-template-parsing"}); 486 auto Results = 487 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 488 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 489 490 AST = 491 buildASTFromCodeWithArgs("template <int N> void f() { char x[N]; g(x); }", 492 {"-fno-delayed-template-parsing"}); 493 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 494 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 495 496 AST = buildASTFromCodeWithArgs( 497 "template <class T> void f(T t) { int x; g(t, x); }", 498 {"-fno-delayed-template-parsing"}); 499 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 500 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(t, x)")); 501 502 AST = buildASTFromCodeWithArgs( 503 "template <class T> void f(T t) { int x; t.mf(x); }", 504 {"-fno-delayed-template-parsing"}); 505 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 506 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("t.mf(x)")); 507 508 AST = buildASTFromCodeWithArgs( 509 "template <class T> struct S;" 510 "template <class T> void f() { S<T> s; int x; s.mf(x); }", 511 {"-fno-delayed-template-parsing"}); 512 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 513 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf(x)")); 514 515 AST = buildASTFromCodeWithArgs( 516 "struct S { template <class T> void mf(); };" 517 "template <class T> void f(S s) { int x; s.mf<T>(x); }", 518 {"-fno-delayed-template-parsing"}); 519 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 520 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("s.mf<T>(x)")); 521 522 AST = buildASTFromCodeWithArgs("template <class F>" 523 "void g(F f) { int x; f(x); } ", 524 {"-fno-delayed-template-parsing"}); 525 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 526 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f(x)")); 527 528 AST = buildASTFromCodeWithArgs( 529 "template <class T> void f() { int x; (void)T(x); }", 530 {"-fno-delayed-template-parsing"}); 531 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 532 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("T(x)")); 533 } 534 535 TEST(ExprMutationAnalyzerTest, ReturnAsValue) { 536 auto AST = buildASTFromCode("int f() { int x; return x; }"); 537 auto Results = 538 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 539 EXPECT_FALSE(isMutated(Results, AST.get())); 540 541 AST = buildASTFromCode("int* f() { int* x; return x; }"); 542 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 543 EXPECT_FALSE(isMutated(Results, AST.get())); 544 545 AST = buildASTFromCode("typedef int* IntPtr;" 546 "IntPtr f() { int* x; return x; }"); 547 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 548 EXPECT_FALSE(isMutated(Results, AST.get())); 549 } 550 551 TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) { 552 const auto AST = buildASTFromCode("int& f() { int x; return x; }"); 553 const auto Results = 554 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 555 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;")); 556 } 557 558 TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) { 559 const auto AST = buildASTFromCode("const int& f() { int x; return x; }"); 560 const auto Results = 561 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 562 EXPECT_FALSE(isMutated(Results, AST.get())); 563 } 564 565 TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRRef) { 566 const auto AST = 567 buildASTFromCode("int&& f() { int x; return static_cast<int &&>(x); }"); 568 const auto Results = 569 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 570 EXPECT_THAT(mutatedBy(Results, AST.get()), 571 ElementsAre("return static_cast<int &&>(x);")); 572 } 573 574 TEST(ExprMutationAnalyzerTest, ReturnAsConstRRef) { 575 const auto AST = buildASTFromCode( 576 "const int&& f() { int x; return static_cast<int&&>(x); }"); 577 const auto Results = 578 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 579 EXPECT_FALSE(isMutated(Results, AST.get())); 580 } 581 582 TEST(ExprMutationAnalyzerTest, TakeAddress) { 583 const auto AST = buildASTFromCode("void g(int*); void f() { int x; g(&x); }"); 584 const auto Results = 585 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 586 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x")); 587 } 588 589 TEST(ExprMutationAnalyzerTest, ArrayToPointerDecay) { 590 const auto AST = 591 buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }"); 592 const auto Results = 593 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 594 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 595 } 596 597 TEST(ExprMutationAnalyzerTest, TemplateWithArrayToPointerDecay) { 598 const auto AST = buildASTFromCodeWithArgs( 599 "template <typename T> struct S { static constexpr int v = 8; };" 600 "template <> struct S<int> { static constexpr int v = 4; };" 601 "void g(char*);" 602 "template <typename T> void f() { char x[S<T>::v]; g(x); }" 603 "template <> void f<int>() { char y[S<int>::v]; g(y); }", 604 {"-fno-delayed-template-parsing"}); 605 const auto ResultsX = 606 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 607 EXPECT_THAT(mutatedBy(ResultsX, AST.get()), ElementsAre("g(x)")); 608 const auto ResultsY = 609 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 610 EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y")); 611 } 612 613 TEST(ExprMutationAnalyzerTest, FollowRefModified) { 614 auto AST = buildASTFromCode( 615 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " 616 "int& r3 = r2; r3 = 10; }"); 617 auto Results = 618 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 619 EXPECT_THAT(mutatedBy(Results, AST.get()), 620 ElementsAre("r0", "r1", "r2", "r3", "r3 = 10")); 621 622 AST = buildASTFromCode("typedef int& IntRefX;" 623 "using IntRefY = int&;" 624 "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;" 625 "decltype((x)) r2 = r1; r2 = 10; }"); 626 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 627 EXPECT_THAT(mutatedBy(Results, AST.get()), 628 ElementsAre("r0", "r1", "r2", "r2 = 10")); 629 } 630 631 TEST(ExprMutationAnalyzerTest, FollowRefNotModified) { 632 auto AST = buildASTFromCode( 633 "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " 634 "int& r3 = r2; int& r4 = r3; int& r5 = r4;}"); 635 auto Results = 636 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 637 EXPECT_FALSE(isMutated(Results, AST.get())); 638 639 AST = buildASTFromCode("void f() { int x; int& r0 = x; const int& r1 = r0;}"); 640 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 641 EXPECT_FALSE(isMutated(Results, AST.get())); 642 643 AST = buildASTFromCode("typedef const int& CIntRefX;" 644 "using CIntRefY = const int&;" 645 "void f() { int x; int& r0 = x; CIntRefX r1 = r0;" 646 "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}"); 647 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 648 EXPECT_FALSE(isMutated(Results, AST.get())); 649 } 650 651 TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) { 652 const auto AST = buildASTFromCode( 653 "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }"); 654 const auto Results = 655 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 656 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10")); 657 } 658 659 TEST(ExprMutationAnalyzerTest, FollowConditionalRefNotModified) { 660 const auto AST = 661 buildASTFromCode("void f() { int x, y; bool b; int& r = b ? x : y; }"); 662 const auto Results = 663 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 664 EXPECT_FALSE(isMutated(Results, AST.get())); 665 } 666 667 TEST(ExprMutationAnalyzerTest, FollowFuncArgModified) { 668 auto AST = buildASTFromCode("template <class T> void g(T&& t) { t = 10; }" 669 "void f() { int x; g(x); }"); 670 auto Results = 671 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 672 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 673 674 AST = buildASTFromCode( 675 "void h(int&);" 676 "template <class... Args> void g(Args&&... args) { h(args...); }" 677 "void f() { int x; g(x); }"); 678 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 679 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 680 681 AST = buildASTFromCode( 682 "void h(int&, int);" 683 "template <class... Args> void g(Args&&... args) { h(args...); }" 684 "void f() { int x, y; g(x, y); }"); 685 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 686 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x, y)")); 687 Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 688 EXPECT_FALSE(isMutated(Results, AST.get())); 689 690 AST = buildASTFromCode( 691 "void h(int, int&);" 692 "template <class... Args> void g(Args&&... args) { h(args...); }" 693 "void f() { int x, y; g(y, x); }"); 694 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 695 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(y, x)")); 696 Results = match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 697 EXPECT_FALSE(isMutated(Results, AST.get())); 698 699 AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t = 10; } };" 700 "void f() { int x; S s(x); }"); 701 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 702 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 703 704 AST = buildASTFromCode( 705 "struct S { template <class T> S(T&& t) : m(++t) { } int m; };" 706 "void f() { int x; S s(x); }"); 707 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 708 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 709 710 AST = buildASTFromCode("template <class U> struct S {" 711 "template <class T> S(T&& t) : m(++t) { } U m; };" 712 "void f() { int x; S<int> s(x); }"); 713 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 714 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 715 716 AST = buildASTFromCode(StdRemoveReference + StdForward + 717 "template <class... Args> void u(Args&...);" 718 "template <class... Args> void h(Args&&... args)" 719 "{ u(std::forward<Args>(args)...); }" 720 "template <class... Args> void g(Args&&... args)" 721 "{ h(std::forward<Args>(args)...); }" 722 "void f() { int x; g(x); }"); 723 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 724 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); 725 } 726 727 TEST(ExprMutationAnalyzerTest, FollowFuncArgNotModified) { 728 auto AST = buildASTFromCode("template <class T> void g(T&&) {}" 729 "void f() { int x; g(x); }"); 730 auto Results = 731 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 732 EXPECT_FALSE(isMutated(Results, AST.get())); 733 734 AST = buildASTFromCode("template <class T> void g(T&& t) { t; }" 735 "void f() { int x; g(x); }"); 736 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 737 EXPECT_FALSE(isMutated(Results, AST.get())); 738 739 AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}" 740 "void f() { int x; g(x); }"); 741 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 742 EXPECT_FALSE(isMutated(Results, AST.get())); 743 744 AST = buildASTFromCode("template <class... Args> void g(Args&&...) {}" 745 "void f() { int y, x; g(y, x); }"); 746 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 747 EXPECT_FALSE(isMutated(Results, AST.get())); 748 749 AST = buildASTFromCode( 750 "void h(int, int&);" 751 "template <class... Args> void g(Args&&... args) { h(args...); }" 752 "void f() { int x, y; g(x, y); }"); 753 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 754 EXPECT_FALSE(isMutated(Results, AST.get())); 755 756 AST = buildASTFromCode("struct S { template <class T> S(T&& t) { t; } };" 757 "void f() { int x; S s(x); }"); 758 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 759 EXPECT_FALSE(isMutated(Results, AST.get())); 760 761 AST = buildASTFromCode( 762 "struct S { template <class T> S(T&& t) : m(t) { } int m; };" 763 "void f() { int x; S s(x); }"); 764 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 765 EXPECT_FALSE(isMutated(Results, AST.get())); 766 767 AST = buildASTFromCode("template <class U> struct S {" 768 "template <class T> S(T&& t) : m(t) { } U m; };" 769 "void f() { int x; S<int> s(x); }"); 770 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 771 EXPECT_FALSE(isMutated(Results, AST.get())); 772 773 AST = buildASTFromCode(StdRemoveReference + StdForward + 774 "template <class... Args> void u(Args...);" 775 "template <class... Args> void h(Args&&... args)" 776 "{ u(std::forward<Args>(args)...); }" 777 "template <class... Args> void g(Args&&... args)" 778 "{ h(std::forward<Args>(args)...); }" 779 "void f() { int x; g(x); }"); 780 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 781 EXPECT_FALSE(isMutated(Results, AST.get())); 782 } 783 784 TEST(ExprMutationAnalyzerTest, ArrayElementModified) { 785 const auto AST = buildASTFromCode("void f() { int x[2]; x[0] = 10; }"); 786 const auto Results = 787 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 788 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10")); 789 } 790 791 TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) { 792 const auto AST = buildASTFromCode("void f() { int x[2]; x[0]; }"); 793 const auto Results = 794 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 795 EXPECT_FALSE(isMutated(Results, AST.get())); 796 } 797 798 TEST(ExprMutationAnalyzerTest, NestedMemberModified) { 799 auto AST = 800 buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " 801 "struct C { B vb; }; C x; x.vb.va.vi = 10; }"); 802 auto Results = 803 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 804 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10")); 805 806 AST = buildASTFromCodeWithArgs( 807 "template <class T> void f() { T x; x.y.z = 10; }", 808 {"-fno-delayed-template-parsing"}); 809 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 810 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); 811 812 AST = buildASTFromCodeWithArgs( 813 "template <class T> struct S;" 814 "template <class T> void f() { S<T> x; x.y.z = 10; }", 815 {"-fno-delayed-template-parsing"}); 816 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 817 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.y.z = 10")); 818 } 819 820 TEST(ExprMutationAnalyzerTest, NestedMemberNotModified) { 821 auto AST = 822 buildASTFromCode("void f() { struct A { int vi; }; struct B { A va; }; " 823 "struct C { B vb; }; C x; x.vb.va.vi; }"); 824 auto Results = 825 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 826 EXPECT_FALSE(isMutated(Results, AST.get())); 827 828 AST = buildASTFromCodeWithArgs("template <class T> void f() { T x; x.y.z; }", 829 {"-fno-delayed-template-parsing"}); 830 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 831 EXPECT_FALSE(isMutated(Results, AST.get())); 832 833 AST = 834 buildASTFromCodeWithArgs("template <class T> struct S;" 835 "template <class T> void f() { S<T> x; x.y.z; }", 836 {"-fno-delayed-template-parsing"}); 837 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 838 EXPECT_FALSE(isMutated(Results, AST.get())); 839 } 840 841 TEST(ExprMutationAnalyzerTest, CastToValue) { 842 const auto AST = 843 buildASTFromCode("void f() { int x; static_cast<double>(x); }"); 844 const auto Results = 845 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 846 EXPECT_FALSE(isMutated(Results, AST.get())); 847 } 848 849 TEST(ExprMutationAnalyzerTest, CastToRefModified) { 850 auto AST = 851 buildASTFromCode("void f() { int x; static_cast<int &>(x) = 10; }"); 852 auto Results = 853 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 854 EXPECT_THAT(mutatedBy(Results, AST.get()), 855 ElementsAre("static_cast<int &>(x) = 10")); 856 857 AST = buildASTFromCode("typedef int& IntRef;" 858 "void f() { int x; static_cast<IntRef>(x) = 10; }"); 859 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 860 EXPECT_THAT(mutatedBy(Results, AST.get()), 861 ElementsAre("static_cast<IntRef>(x) = 10")); 862 } 863 864 TEST(ExprMutationAnalyzerTest, CastToRefNotModified) { 865 const auto AST = 866 buildASTFromCode("void f() { int x; static_cast<int&>(x); }"); 867 const auto Results = 868 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 869 EXPECT_FALSE(isMutated(Results, AST.get())); 870 } 871 872 TEST(ExprMutationAnalyzerTest, CastToConstRef) { 873 auto AST = 874 buildASTFromCode("void f() { int x; static_cast<const int&>(x); }"); 875 auto Results = 876 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 877 EXPECT_FALSE(isMutated(Results, AST.get())); 878 879 AST = buildASTFromCode("typedef const int& CIntRef;" 880 "void f() { int x; static_cast<CIntRef>(x); }"); 881 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 882 EXPECT_FALSE(isMutated(Results, AST.get())); 883 } 884 885 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) { 886 const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }"); 887 const auto Results = 888 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 889 EXPECT_FALSE(isMutated(Results, AST.get())); 890 } 891 892 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) { 893 const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }"); 894 const auto Results = 895 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 896 EXPECT_FALSE(isMutated(Results, AST.get())); 897 } 898 899 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) { 900 const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }"); 901 const auto Results = 902 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 903 EXPECT_THAT(mutatedBy(Results, AST.get()), 904 ElementsAre(ResultOf(removeSpace, "[&](){x=10;}"))); 905 } 906 907 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) { 908 const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }"); 909 const auto Results = 910 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 911 EXPECT_THAT(mutatedBy(Results, AST.get()), 912 ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}"))); 913 } 914 915 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) { 916 auto AST = 917 buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }"); 918 auto Results = 919 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 920 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); 921 922 AST = buildASTFromCode("typedef int& IntRef;" 923 "void f() { int x[2]; for (IntRef e : x) e = 10; }"); 924 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 925 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); 926 } 927 928 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefNotModified) { 929 const auto AST = 930 buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }"); 931 const auto Results = 932 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 933 EXPECT_FALSE(isMutated(Results, AST.get())); 934 } 935 936 TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) { 937 auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }"); 938 auto Results = 939 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 940 EXPECT_FALSE(isMutated(Results, AST.get())); 941 942 AST = 943 buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }"); 944 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 945 EXPECT_FALSE(isMutated(Results, AST.get())); 946 947 AST = buildASTFromCode( 948 "typedef int* IntPtr;" 949 "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }"); 950 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 951 EXPECT_FALSE(isMutated(Results, AST.get())); 952 } 953 954 TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) { 955 auto AST = 956 buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }"); 957 auto Results = 958 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 959 EXPECT_FALSE(isMutated(Results, AST.get())); 960 961 AST = buildASTFromCode("typedef const int& CIntRef;" 962 "void f() { int x[2]; for (CIntRef e : x) e; }"); 963 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 964 EXPECT_FALSE(isMutated(Results, AST.get())); 965 } 966 967 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) { 968 const auto AST = 969 buildASTFromCode("struct V { int* begin(); int* end(); };" 970 "void f() { V x; for (int& e : x) e = 10; }"); 971 const auto Results = 972 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 973 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); 974 } 975 976 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) { 977 const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };" 978 "void f() { V x; for (int& e : x) e; }"); 979 const auto Results = 980 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 981 EXPECT_FALSE(isMutated(Results, AST.get())); 982 } 983 984 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) { 985 const auto AST = buildASTFromCode( 986 "struct V { const int* begin() const; const int* end() const; };" 987 "void f() { V x; for (int e : x) e; }"); 988 const auto Results = 989 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 990 EXPECT_FALSE(isMutated(Results, AST.get())); 991 } 992 993 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) { 994 const auto AST = buildASTFromCode( 995 "struct V { const int* begin() const; const int* end() const; };" 996 "void f() { V x; for (const int& e : x) e; }"); 997 const auto Results = 998 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 999 EXPECT_FALSE(isMutated(Results, AST.get())); 1000 } 1001 1002 TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) { 1003 auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }"); 1004 auto Results = 1005 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1006 EXPECT_FALSE(isMutated(Results, AST.get())); 1007 1008 AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }"); 1009 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1010 EXPECT_FALSE(isMutated(Results, AST.get())); 1011 1012 AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }"); 1013 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1014 EXPECT_FALSE(isMutated(Results, AST.get())); 1015 1016 AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }"); 1017 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1018 EXPECT_FALSE(isMutated(Results, AST.get())); 1019 1020 AST = buildASTFromCode("void f() { int x; alignof(x = 10); }"); 1021 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1022 EXPECT_FALSE(isMutated(Results, AST.get())); 1023 1024 AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }"); 1025 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1026 EXPECT_FALSE(isMutated(Results, AST.get())); 1027 1028 AST = buildASTFromCodeWithArgs("namespace std { class type_info; }" 1029 "void f() { int x; typeid(x = 10); }", 1030 {"-frtti"}); 1031 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1032 EXPECT_FALSE(isMutated(Results, AST.get())); 1033 1034 AST = buildASTFromCode( 1035 "void f() { int x; _Generic(x = 10, int: 0, default: 1); }"); 1036 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1037 EXPECT_FALSE(isMutated(Results, AST.get())); 1038 } 1039 1040 TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) { 1041 auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }"); 1042 auto Results = 1043 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1044 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++")); 1045 1046 AST = buildASTFromCodeWithArgs( 1047 "namespace std { class type_info; }" 1048 "struct A { virtual ~A(); }; struct B : A {};" 1049 "struct X { A& f(); }; void f() { X x; typeid(x.f()); }", 1050 {"-frtti"}); 1051 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1052 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()")); 1053 } 1054 1055 TEST(ExprMutationAnalyzerTest, UniquePtr) { 1056 const std::string UniquePtrDef = 1057 "template <class T> struct UniquePtr {" 1058 " UniquePtr();" 1059 " UniquePtr(const UniquePtr&) = delete;" 1060 " UniquePtr(UniquePtr&&);" 1061 " UniquePtr& operator=(const UniquePtr&) = delete;" 1062 " UniquePtr& operator=(UniquePtr&&);" 1063 " T& operator*() const;" 1064 " T* operator->() const;" 1065 "};"; 1066 1067 auto AST = buildASTFromCode(UniquePtrDef + 1068 "void f() { UniquePtr<int> x; *x = 10; }"); 1069 auto Results = 1070 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1071 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10")); 1072 1073 AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr<int> x; *x; }"); 1074 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1075 EXPECT_FALSE(isMutated(Results, AST.get())); 1076 1077 AST = buildASTFromCode(UniquePtrDef + 1078 "void f() { UniquePtr<const int> x; *x; }"); 1079 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1080 EXPECT_FALSE(isMutated(Results, AST.get())); 1081 1082 AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };" 1083 "void f() { UniquePtr<S> x; x->v; }"); 1084 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1085 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1086 1087 AST = buildASTFromCode(UniquePtrDef + 1088 "struct S { int v; };" 1089 "void f() { UniquePtr<const S> x; x->v; }"); 1090 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1091 EXPECT_FALSE(isMutated(Results, AST.get())); 1092 1093 AST = 1094 buildASTFromCode(UniquePtrDef + "struct S { void mf(); };" 1095 "void f() { UniquePtr<S> x; x->mf(); }"); 1096 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1097 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1098 1099 AST = buildASTFromCode(UniquePtrDef + 1100 "struct S { void mf() const; };" 1101 "void f() { UniquePtr<const S> x; x->mf(); }"); 1102 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1103 EXPECT_FALSE(isMutated(Results, AST.get())); 1104 1105 AST = buildASTFromCodeWithArgs( 1106 UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }", 1107 {"-fno-delayed-template-parsing"}); 1108 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1109 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()")); 1110 } 1111 1112 } // namespace clang 1113