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 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, CommaExprWithAnAssigment) { 886 const auto AST = buildASTFromCodeWithArgs( 887 "void f() { int x; int y; (x, y) = 5; }", {"-Wno-unused-value"}); 888 const auto Results = 889 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 890 EXPECT_TRUE(isMutated(Results, AST.get())); 891 } 892 893 TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) { 894 const auto AST = buildASTFromCodeWithArgs( 895 "void f() { int x; int y; (x, y)++; }", {"-Wno-unused-value"}); 896 const auto Results = 897 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 898 EXPECT_TRUE(isMutated(Results, AST.get())); 899 } 900 901 TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) { 902 const auto AST = buildASTFromCodeWithArgs( 903 "class A { public: int mem; void f() { mem ++; } };" 904 "void fn() { A o1, o2; (o1, o2).f(); }", 905 {"-Wno-unused-value"}); 906 const auto Results = 907 match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext()); 908 EXPECT_TRUE(isMutated(Results, AST.get())); 909 } 910 911 TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) { 912 const auto AST = buildASTFromCodeWithArgs( 913 "class A { public: int mem; void f() const { } };" 914 "void fn() { A o1, o2; (o1, o2).f(); }", 915 {"-Wno-unused-value"}); 916 const auto Results = 917 match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext()); 918 EXPECT_FALSE(isMutated(Results, AST.get())); 919 } 920 921 TEST(ExprMutationAnalyzerTest, CommaExprWithCallExpr) { 922 const auto AST = 923 buildASTFromCodeWithArgs("class A { public: int mem; void f(A &O1) {} };" 924 "void fn() { A o1, o2; o2.f((o2, o1)); }", 925 {"-Wno-unused-value"}); 926 const auto Results = 927 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 928 EXPECT_TRUE(isMutated(Results, AST.get())); 929 } 930 931 TEST(ExprMutationAnalyzerTest, CommaExprWithCallUnresolved) { 932 auto AST = buildASTFromCodeWithArgs( 933 "template <class T> struct S;" 934 "template <class T> void f() { S<T> s; int x, y; s.mf((y, x)); }", 935 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 936 auto Results = 937 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 938 EXPECT_TRUE(isMutated(Results, AST.get())); 939 940 AST = buildASTFromCodeWithArgs( 941 "template <class T> void f(T t) { int x, y; g(t, (y, x)); }", 942 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 943 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 944 EXPECT_TRUE(isMutated(Results, AST.get())); 945 } 946 947 TEST(ExprMutationAnalyzerTest, CommaExprParmRef) { 948 const auto AST = 949 buildASTFromCodeWithArgs("class A { public: int mem;};" 950 "extern void fn(A &o1);" 951 "void fn2 () { A o1, o2; fn((o2, o1)); } ", 952 {"-Wno-unused-value"}); 953 const auto Results = 954 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 955 EXPECT_TRUE(isMutated(Results, AST.get())); 956 } 957 958 TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) { 959 const auto AST = buildASTFromCodeWithArgs("class A { public: int mem;};" 960 "void fn () { A o1, o2;" 961 "void *addr = &(o2, o1); } ", 962 {"-Wno-unused-value"}); 963 const auto Results = 964 match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext()); 965 EXPECT_TRUE(isMutated(Results, AST.get())); 966 } 967 968 TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsValue) { 969 auto AST = buildASTFromCodeWithArgs("int f() { int x, y; return (x, y); }", 970 {"-Wno-unused-value"}); 971 auto Results = 972 match(withEnclosingCompound(declRefTo("y")), AST->getASTContext()); 973 EXPECT_FALSE(isMutated(Results, AST.get())); 974 } 975 976 TEST(ExprMutationAnalyzerTest, CommaEpxrAsReturnAsNonConstRef) { 977 const auto AST = buildASTFromCodeWithArgs( 978 "int& f() { int x, y; return (y, x); }", {"-Wno-unused-value"}); 979 const auto Results = 980 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 981 EXPECT_TRUE(isMutated(Results, AST.get())); 982 } 983 984 TEST(ExprMutationAnalyzerTest, CommaExprAsArrayToPointerDecay) { 985 const auto AST = 986 buildASTFromCodeWithArgs("void g(int*); " 987 "void f() { int x[2], y[2]; g((y, x)); }", 988 {"-Wno-unused-value"}); 989 const auto Results = 990 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 991 EXPECT_TRUE(isMutated(Results, AST.get())); 992 } 993 994 TEST(ExprMutationAnalyzerTest, CommaExprAsUniquePtr) { 995 const std::string UniquePtrDef = "template <class T> struct UniquePtr {" 996 " UniquePtr();" 997 " UniquePtr(const UniquePtr&) = delete;" 998 " T& operator*() const;" 999 " T* operator->() const;" 1000 "};"; 1001 const auto AST = buildASTFromCodeWithArgs( 1002 UniquePtrDef + "template <class T> void f() " 1003 "{ UniquePtr<T> x; UniquePtr<T> y;" 1004 " (y, x)->mf(); }", 1005 {"-fno-delayed-template-parsing", "-Wno-unused-value"}); 1006 const auto Results = 1007 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1008 EXPECT_TRUE(isMutated(Results, AST.get())); 1009 } 1010 1011 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) { 1012 const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }"); 1013 const auto Results = 1014 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1015 EXPECT_FALSE(isMutated(Results, AST.get())); 1016 } 1017 1018 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) { 1019 const auto AST = buildASTFromCode("void f() { int x; [x]() { x; }; }"); 1020 const auto Results = 1021 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1022 EXPECT_FALSE(isMutated(Results, AST.get())); 1023 } 1024 1025 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) { 1026 const auto AST = buildASTFromCode("void f() { int x; [&]() { x = 10; }; }"); 1027 const auto Results = 1028 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1029 EXPECT_THAT(mutatedBy(Results, AST.get()), 1030 ElementsAre(ResultOf(removeSpace, "[&](){x=10;}"))); 1031 } 1032 1033 TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) { 1034 const auto AST = buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }"); 1035 const auto Results = 1036 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1037 EXPECT_THAT(mutatedBy(Results, AST.get()), 1038 ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}"))); 1039 } 1040 1041 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) { 1042 auto AST = 1043 buildASTFromCode("void f() { int x[2]; for (int& e : x) e = 10; }"); 1044 auto Results = 1045 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1046 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); 1047 1048 AST = buildASTFromCode("typedef int& IntRef;" 1049 "void f() { int x[2]; for (IntRef e : x) e = 10; }"); 1050 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1051 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); 1052 } 1053 1054 TEST(ExprMutationAnalyzerTest, RangeForArrayByRefNotModified) { 1055 const auto AST = 1056 buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }"); 1057 const auto Results = 1058 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1059 EXPECT_FALSE(isMutated(Results, AST.get())); 1060 } 1061 1062 TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) { 1063 auto AST = buildASTFromCode("void f() { int x[2]; for (int e : x) e = 10; }"); 1064 auto Results = 1065 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1066 EXPECT_FALSE(isMutated(Results, AST.get())); 1067 1068 AST = 1069 buildASTFromCode("void f() { int* x[2]; for (int* e : x) e = nullptr; }"); 1070 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1071 EXPECT_FALSE(isMutated(Results, AST.get())); 1072 1073 AST = buildASTFromCode( 1074 "typedef int* IntPtr;" 1075 "void f() { int* x[2]; for (IntPtr e : x) e = nullptr; }"); 1076 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1077 EXPECT_FALSE(isMutated(Results, AST.get())); 1078 } 1079 1080 TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) { 1081 auto AST = 1082 buildASTFromCode("void f() { int x[2]; for (const int& e : x) e; }"); 1083 auto Results = 1084 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1085 EXPECT_FALSE(isMutated(Results, AST.get())); 1086 1087 AST = buildASTFromCode("typedef const int& CIntRef;" 1088 "void f() { int x[2]; for (CIntRef e : x) e; }"); 1089 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1090 EXPECT_FALSE(isMutated(Results, AST.get())); 1091 } 1092 1093 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) { 1094 const auto AST = 1095 buildASTFromCode("struct V { int* begin(); int* end(); };" 1096 "void f() { V x; for (int& e : x) e = 10; }"); 1097 const auto Results = 1098 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1099 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); 1100 } 1101 1102 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) { 1103 const auto AST = buildASTFromCode("struct V { int* begin(); int* end(); };" 1104 "void f() { V x; for (int& e : x) e; }"); 1105 const auto Results = 1106 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1107 EXPECT_FALSE(isMutated(Results, AST.get())); 1108 } 1109 1110 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) { 1111 const auto AST = buildASTFromCode( 1112 "struct V { const int* begin() const; const int* end() const; };" 1113 "void f() { V x; for (int e : x) e; }"); 1114 const auto Results = 1115 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1116 EXPECT_FALSE(isMutated(Results, AST.get())); 1117 } 1118 1119 TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) { 1120 const auto AST = buildASTFromCode( 1121 "struct V { const int* begin() const; const int* end() const; };" 1122 "void f() { V x; for (const int& e : x) e; }"); 1123 const auto Results = 1124 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1125 EXPECT_FALSE(isMutated(Results, AST.get())); 1126 } 1127 1128 TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) { 1129 auto AST = buildASTFromCode("void f() { int x, y; decltype(x = 10) z = y; }"); 1130 auto Results = 1131 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1132 EXPECT_FALSE(isMutated(Results, AST.get())); 1133 1134 AST = buildASTFromCode("void f() { int x, y; __typeof(x = 10) z = y; }"); 1135 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1136 EXPECT_FALSE(isMutated(Results, AST.get())); 1137 1138 AST = buildASTFromCode("void f() { int x, y; __typeof__(x = 10) z = y; }"); 1139 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1140 EXPECT_FALSE(isMutated(Results, AST.get())); 1141 1142 AST = buildASTFromCode("void f() { int x; sizeof(x = 10); }"); 1143 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1144 EXPECT_FALSE(isMutated(Results, AST.get())); 1145 1146 AST = buildASTFromCode("void f() { int x; alignof(x = 10); }"); 1147 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1148 EXPECT_FALSE(isMutated(Results, AST.get())); 1149 1150 AST = buildASTFromCode("void f() { int x; noexcept(x = 10); }"); 1151 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1152 EXPECT_FALSE(isMutated(Results, AST.get())); 1153 1154 AST = buildASTFromCodeWithArgs("namespace std { class type_info; }" 1155 "void f() { int x; typeid(x = 10); }", 1156 {"-frtti"}); 1157 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1158 EXPECT_FALSE(isMutated(Results, AST.get())); 1159 1160 AST = buildASTFromCode( 1161 "void f() { int x; _Generic(x = 10, int: 0, default: 1); }"); 1162 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1163 EXPECT_FALSE(isMutated(Results, AST.get())); 1164 } 1165 1166 TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) { 1167 auto AST = buildASTFromCode("void f() { int x; sizeof(int[x++]); }"); 1168 auto Results = 1169 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1170 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++")); 1171 1172 AST = buildASTFromCodeWithArgs( 1173 "namespace std { class type_info; }" 1174 "struct A { virtual ~A(); }; struct B : A {};" 1175 "struct X { A& f(); }; void f() { X x; typeid(x.f()); }", 1176 {"-frtti"}); 1177 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1178 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()")); 1179 } 1180 1181 TEST(ExprMutationAnalyzerTest, UniquePtr) { 1182 const std::string UniquePtrDef = 1183 "template <class T> struct UniquePtr {" 1184 " UniquePtr();" 1185 " UniquePtr(const UniquePtr&) = delete;" 1186 " UniquePtr(UniquePtr&&);" 1187 " UniquePtr& operator=(const UniquePtr&) = delete;" 1188 " UniquePtr& operator=(UniquePtr&&);" 1189 " T& operator*() const;" 1190 " T* operator->() const;" 1191 "};"; 1192 1193 auto AST = buildASTFromCode(UniquePtrDef + 1194 "void f() { UniquePtr<int> x; *x = 10; }"); 1195 auto Results = 1196 match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1197 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("* x = 10")); 1198 1199 AST = buildASTFromCode(UniquePtrDef + "void f() { UniquePtr<int> x; *x; }"); 1200 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1201 EXPECT_FALSE(isMutated(Results, AST.get())); 1202 1203 AST = buildASTFromCode(UniquePtrDef + 1204 "void f() { UniquePtr<const int> x; *x; }"); 1205 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1206 EXPECT_FALSE(isMutated(Results, AST.get())); 1207 1208 AST = buildASTFromCode(UniquePtrDef + "struct S { int v; };" 1209 "void f() { UniquePtr<S> x; x->v; }"); 1210 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1211 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1212 1213 AST = buildASTFromCode(UniquePtrDef + 1214 "struct S { int v; };" 1215 "void f() { UniquePtr<const S> x; x->v; }"); 1216 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1217 EXPECT_FALSE(isMutated(Results, AST.get())); 1218 1219 AST = 1220 buildASTFromCode(UniquePtrDef + "struct S { void mf(); };" 1221 "void f() { UniquePtr<S> x; x->mf(); }"); 1222 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1223 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x")); 1224 1225 AST = buildASTFromCode(UniquePtrDef + 1226 "struct S { void mf() const; };" 1227 "void f() { UniquePtr<const S> x; x->mf(); }"); 1228 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1229 EXPECT_FALSE(isMutated(Results, AST.get())); 1230 1231 AST = buildASTFromCodeWithArgs( 1232 UniquePtrDef + "template <class T> void f() { UniquePtr<T> x; x->mf(); }", 1233 {"-fno-delayed-template-parsing"}); 1234 Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); 1235 EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()")); 1236 } 1237 1238 TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) { 1239 const std::string Reproducer = 1240 "namespace std {" 1241 "template <class T> T forward(T & A) { return static_cast<T&&>(A); }" 1242 "template <class T> struct __bind {" 1243 " T f;" 1244 " template <class V> __bind(T v, V &&) : f(forward(v)) {}" 1245 "};" 1246 "}" 1247 "void f() {" 1248 " int x = 42;" 1249 " auto Lambda = [] {};" 1250 " std::__bind<decltype(Lambda)>(Lambda, x);" 1251 "}"; 1252 auto AST11 = buildASTFromCodeWithArgs(Reproducer, {"-std=c++11"}); 1253 auto Results11 = 1254 match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext()); 1255 EXPECT_FALSE(isMutated(Results11, AST11.get())); 1256 } 1257 } // namespace clang 1258