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