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