1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <assert.h> 6 #include <stdlib.h> 7 #include <algorithm> 8 #include <memory> 9 #include <string> 10 11 #include "clang/AST/ASTContext.h" 12 #include "clang/AST/ParentMap.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/ASTMatchers/ASTMatchersMacros.h" 16 #include "clang/Analysis/CFG.h" 17 #include "clang/Basic/SourceManager.h" 18 #include "clang/Frontend/FrontendActions.h" 19 #include "clang/Lex/Lexer.h" 20 #include "clang/Tooling/CommonOptionsParser.h" 21 #include "clang/Tooling/Refactoring.h" 22 #include "clang/Tooling/Tooling.h" 23 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/TargetSelect.h" 25 26 using Replacements = std::vector<clang::tooling::Replacement>; 27 using clang::ASTContext; 28 using clang::CFG; 29 using clang::CFGBlock; 30 using clang::CFGLifetimeEnds; 31 using clang::CFGStmt; 32 using clang::CallExpr; 33 using clang::Decl; 34 using clang::DeclRefExpr; 35 using clang::FunctionDecl; 36 using clang::LambdaExpr; 37 using clang::Stmt; 38 using clang::UnaryOperator; 39 using clang::ast_type_traits::DynTypedNode; 40 using clang::tooling::CommonOptionsParser; 41 using namespace clang::ast_matchers; 42 43 namespace { 44 45 class Rewriter { 46 public: 47 virtual ~Rewriter() {} 48 }; 49 50 // Removes unneeded base::Passed() on a parameter of base::BindOnce(). 51 // Example: 52 // // Before 53 // base::BindOnce(&Foo, base::Passed(&bar)); 54 // base::BindOnce(&Foo, base::Passed(std::move(baz))); 55 // base::BindOnce(&Foo, base::Passed(qux)); 56 // 57 // // After 58 // base::BindOnce(&Foo, std::move(bar)); 59 // base::BindOnce(&Foo, std::move(baz)); 60 // base::BindOnce(&Foo, std::move(*qux)); 61 class PassedToMoveRewriter : public MatchFinder::MatchCallback, 62 public Rewriter { 63 public: 64 explicit PassedToMoveRewriter(Replacements* replacements) 65 : replacements_(replacements) {} 66 67 StatementMatcher GetMatcher() { 68 auto is_passed = namedDecl(hasName("::base::Passed")); 69 auto is_bind_once_call = callee(namedDecl(hasName("::base::BindOnce"))); 70 71 // Matches base::Passed() call on a base::BindOnce() argument. 72 return callExpr(is_bind_once_call, 73 hasAnyArgument(ignoringImplicit( 74 callExpr(callee(is_passed)).bind("target")))); 75 } 76 77 void run(const MatchFinder::MatchResult& result) override { 78 auto* target = result.Nodes.getNodeAs<CallExpr>("target"); 79 auto* callee = target->getCallee()->IgnoreImpCasts(); 80 81 auto* callee_decl = clang::dyn_cast<DeclRefExpr>(callee)->getDecl(); 82 auto* passed_decl = clang::dyn_cast<FunctionDecl>(callee_decl); 83 auto* param_type = passed_decl->getParamDecl(0)->getType().getTypePtr(); 84 85 if (param_type->isRValueReferenceType()) { 86 // base::Passed(xxx) -> xxx. 87 // The parameter type is already an rvalue reference. 88 // Example: 89 // std::unique_ptr<int> foo(); 90 // std::unique_ptr<int> bar; 91 // base::Passed(foo()); 92 // base::Passed(std::move(bar)); 93 // In these cases, we can just remove base::Passed. 94 auto left = clang::CharSourceRange::getTokenRange( 95 result.SourceManager->getSpellingLoc(target->getLocStart()), 96 result.SourceManager->getSpellingLoc(target->getArg(0)->getExprLoc()) 97 .getLocWithOffset(-1)); 98 auto r_paren = clang::CharSourceRange::getTokenRange( 99 result.SourceManager->getSpellingLoc(target->getRParenLoc()), 100 result.SourceManager->getSpellingLoc(target->getRParenLoc())); 101 replacements_->emplace_back(*result.SourceManager, left, " "); 102 replacements_->emplace_back(*result.SourceManager, r_paren, " "); 103 return; 104 } 105 106 if (!param_type->isPointerType()) 107 return; 108 109 auto* passed_arg = target->getArg(0)->IgnoreImpCasts(); 110 if (auto* unary = clang::dyn_cast<clang::UnaryOperator>(passed_arg)) { 111 if (unary->getOpcode() == clang::UO_AddrOf) { 112 // base::Passed(&xxx) -> std::move(xxx). 113 auto left = clang::CharSourceRange::getTokenRange( 114 result.SourceManager->getSpellingLoc(target->getLocStart()), 115 result.SourceManager->getSpellingLoc( 116 target->getArg(0)->getExprLoc())); 117 replacements_->emplace_back(*result.SourceManager, left, "std::move("); 118 return; 119 } 120 } 121 122 // base::Passed(xxx) -> std::move(*xxx) 123 auto left = clang::CharSourceRange::getTokenRange( 124 result.SourceManager->getSpellingLoc(target->getLocStart()), 125 result.SourceManager->getSpellingLoc(target->getArg(0)->getExprLoc()) 126 .getLocWithOffset(-1)); 127 replacements_->emplace_back(*result.SourceManager, left, "std::move(*"); 128 } 129 130 private: 131 Replacements* replacements_; 132 }; 133 134 // Replace base::Bind() to base::BindOnce() where resulting base::Callback is 135 // implicitly converted into base::OnceCallback. 136 // Example: 137 // // Before 138 // base::PostTask(FROM_HERE, base::Bind(&Foo)); 139 // base::OnceCallback<void()> cb = base::Bind(&Foo); 140 // 141 // // After 142 // base::PostTask(FROM_HERE, base::BindOnce(&Foo)); 143 // base::OnceCallback<void()> cb = base::BindOnce(&Foo); 144 class BindOnceRewriter : public MatchFinder::MatchCallback, public Rewriter { 145 public: 146 explicit BindOnceRewriter(Replacements* replacements) 147 : replacements_(replacements) {} 148 149 StatementMatcher GetMatcher() { 150 auto is_once_callback = hasType(hasCanonicalType(hasDeclaration( 151 classTemplateSpecializationDecl(hasName("::base::OnceCallback"))))); 152 auto is_repeating_callback = 153 hasType(hasCanonicalType(hasDeclaration(classTemplateSpecializationDecl( 154 hasName("::base::RepeatingCallback"))))); 155 156 auto bind_call = 157 callExpr(callee(namedDecl(hasName("::base::Bind")))).bind("target"); 158 auto parameter_construction = 159 cxxConstructExpr(is_repeating_callback, argumentCountIs(1), 160 hasArgument(0, ignoringImplicit(bind_call))); 161 auto constructor_conversion = cxxConstructExpr( 162 is_once_callback, argumentCountIs(1), 163 hasArgument(0, ignoringImplicit(parameter_construction))); 164 return implicitCastExpr(is_once_callback, 165 hasSourceExpression(constructor_conversion)); 166 } 167 168 void run(const MatchFinder::MatchResult& result) override { 169 auto* target = result.Nodes.getNodeAs<clang::CallExpr>("target"); 170 auto* callee = target->getCallee(); 171 auto range = clang::CharSourceRange::getTokenRange( 172 result.SourceManager->getSpellingLoc(callee->getLocEnd()), 173 result.SourceManager->getSpellingLoc(callee->getLocEnd())); 174 replacements_->emplace_back(*result.SourceManager, range, "BindOnce"); 175 } 176 177 private: 178 Replacements* replacements_; 179 }; 180 181 // Converts pass-by-const-ref base::Callback's to pass-by-value. 182 // Example: 183 // // Before 184 // using BarCallback = base::Callback<void(void*)>; 185 // void Foo(const base::Callback<void(int)>& cb); 186 // void Bar(const BarCallback& cb); 187 // 188 // // After 189 // using BarCallback = base::Callback<void(void*)>; 190 // void Foo(base::Callback<void(int)> cb); 191 // void Bar(BarCallback cb); 192 class PassByValueRewriter : public MatchFinder::MatchCallback, public Rewriter { 193 public: 194 explicit PassByValueRewriter(Replacements* replacements) 195 : replacements_(replacements) {} 196 197 DeclarationMatcher GetMatcher() { 198 auto is_repeating_callback = 199 namedDecl(hasName("::base::RepeatingCallback")); 200 return parmVarDecl( 201 hasType(hasCanonicalType(references(is_repeating_callback)))) 202 .bind("target"); 203 } 204 205 void run(const MatchFinder::MatchResult& result) override { 206 auto* target = result.Nodes.getNodeAs<clang::ParmVarDecl>("target"); 207 auto qual_type = target->getType(); 208 auto* ref_type = 209 clang::dyn_cast<clang::LValueReferenceType>(qual_type.getTypePtr()); 210 if (!ref_type || !ref_type->getPointeeType().isLocalConstQualified()) 211 return; 212 213 // Remove the leading `const` and the following `&`. 214 auto type_loc = target->getTypeSourceInfo()->getTypeLoc(); 215 auto const_keyword = clang::CharSourceRange::getTokenRange( 216 result.SourceManager->getSpellingLoc(target->getLocStart()), 217 result.SourceManager->getSpellingLoc(target->getLocStart())); 218 auto lvalue_ref = clang::CharSourceRange::getTokenRange( 219 result.SourceManager->getSpellingLoc(type_loc.getLocEnd()), 220 result.SourceManager->getSpellingLoc(type_loc.getLocEnd())); 221 replacements_->emplace_back(*result.SourceManager, const_keyword, " "); 222 replacements_->emplace_back(*result.SourceManager, lvalue_ref, " "); 223 } 224 225 private: 226 Replacements* replacements_; 227 }; 228 229 // Adds std::move() to base::RepeatingCallback<> where it looks relevant. 230 // Example: 231 // // Before 232 // void Foo(base::Callback<void(int)> cb1) { 233 // base::Closure cb2 = base::Bind(cb1, 42); 234 // PostTask(FROM_HERE, cb2); 235 // } 236 // 237 // // After 238 // void Foo(base::Callback<void(int)> cb1) { 239 // base::Closure cb2 = base::Bind(std::move(cb1), 42); 240 // PostTask(FROM_HERE, std::move(cb2)); 241 // } 242 class AddStdMoveRewriter : public MatchFinder::MatchCallback, public Rewriter { 243 public: 244 explicit AddStdMoveRewriter(Replacements* replacements) 245 : replacements_(replacements) {} 246 247 StatementMatcher GetMatcher() { 248 return declRefExpr( 249 hasType(hasCanonicalType(hasDeclaration( 250 namedDecl(hasName("::base::RepeatingCallback"))))), 251 anyOf(hasAncestor(cxxConstructorDecl().bind("enclosing_ctor")), 252 hasAncestor(functionDecl().bind("enclosing_func")), 253 hasAncestor(lambdaExpr().bind("enclosing_lambda")))) 254 .bind("target"); 255 } 256 257 // Build Control Flow Graph (CFG) for |stmt| and populate class members with 258 // the content of the graph. Returns true if the analysis finished 259 // successfully. 260 bool ExtractCFGContentToMembers(Stmt* stmt, ASTContext* context) { 261 // Try to make a cache entry. The failure implies it's already in the cache. 262 auto inserted = cfg_cache_.emplace(stmt, nullptr); 263 if (!inserted.second) 264 return !!inserted.first->second; 265 266 std::unique_ptr<CFG>& cfg = inserted.first->second; 267 CFG::BuildOptions opts; 268 opts.AddInitializers = true; 269 opts.AddLifetime = true; 270 opts.AddStaticInitBranches = true; 271 cfg = CFG::buildCFG(nullptr, stmt, context, opts); 272 273 // CFG construction may fail. Report it to the caller. 274 if (!cfg) 275 return false; 276 if (!parent_map_) 277 parent_map_ = llvm::make_unique<clang::ParentMap>(stmt); 278 else 279 parent_map_->addStmt(stmt); 280 281 // Populate |top_stmts_|, that contains Stmts that is evaluated in its own 282 // CFGElement. 283 for (auto* block : *cfg) { 284 for (auto& elem : *block) { 285 if (auto stmt = elem.getAs<CFGStmt>()) 286 top_stmts_.insert(stmt->getStmt()); 287 } 288 } 289 290 // Populate |enclosing_block_|, that maps a Stmt to a CFGBlock that contains 291 // the Stmt. 292 std::function<void(const CFGBlock*, const Stmt*)> recursive_set_enclosing = 293 [&](const CFGBlock* block, const Stmt* stmt) { 294 enclosing_block_[stmt] = block; 295 for (auto* c : stmt->children()) { 296 if (!c) 297 continue; 298 if (top_stmts_.find(c) != top_stmts_.end()) 299 continue; 300 recursive_set_enclosing(block, c); 301 } 302 }; 303 for (auto* block : *cfg) { 304 for (auto& elem : *block) { 305 if (auto stmt = elem.getAs<CFGStmt>()) 306 recursive_set_enclosing(block, stmt->getStmt()); 307 } 308 } 309 310 return true; 311 } 312 313 const Stmt* EnclosingCxxStatement(const Stmt* stmt) { 314 while (true) { 315 const Stmt* parent = parent_map_->getParentIgnoreParenCasts(stmt); 316 assert(parent); 317 switch (parent->getStmtClass()) { 318 case Stmt::CompoundStmtClass: 319 case Stmt::ForStmtClass: 320 case Stmt::CXXForRangeStmtClass: 321 case Stmt::WhileStmtClass: 322 case Stmt::DoStmtClass: 323 case Stmt::IfStmtClass: 324 325 // Other candidates: 326 // Stmt::CXXTryStmtClass 327 // Stmt::CXXCatchStmtClass 328 // Stmt::CapturedStmtClass 329 // Stmt::SwitchStmtClass 330 // Stmt::SwitchCaseClass 331 return stmt; 332 default: 333 stmt = parent; 334 break; 335 } 336 } 337 } 338 339 bool WasPointerTaken(const Stmt* stmt, const Decl* decl) { 340 std::function<bool(const Stmt*)> visit_stmt = [&](const Stmt* stmt) { 341 if (auto* op = clang::dyn_cast<UnaryOperator>(stmt)) { 342 if (op->getOpcode() == clang::UO_AddrOf) { 343 auto* ref = clang::dyn_cast<DeclRefExpr>(op->getSubExpr()); 344 // |ref| may be null if the sub-expr has a dependent type. 345 if (ref && ref->getDecl() == decl) 346 return true; 347 } 348 } 349 350 for (auto* c : stmt->children()) { 351 if (!c) 352 continue; 353 if (visit_stmt(c)) 354 return true; 355 } 356 return false; 357 }; 358 return visit_stmt(stmt); 359 } 360 361 bool HasCapturingLambda(const Stmt* stmt, const Decl* decl) { 362 std::function<bool(const Stmt*)> visit_stmt = [&](const Stmt* stmt) { 363 if (auto* l = clang::dyn_cast<LambdaExpr>(stmt)) { 364 for (auto c : l->captures()) { 365 if (c.getCapturedVar() == decl) 366 return true; 367 } 368 } 369 370 for (auto* c : stmt->children()) { 371 if (!c) 372 continue; 373 374 if (visit_stmt(c)) 375 return true; 376 } 377 378 return false; 379 }; 380 return visit_stmt(stmt); 381 } 382 383 // Returns true if there are multiple occurrences to |decl| in one of C++ 384 // statements in |stmt|. 385 bool HasUnorderedOccurrences(const Decl* decl, const Stmt* stmt) { 386 int count = 0; 387 std::function<void(const Stmt*)> visit_stmt = [&](const Stmt* s) { 388 if (auto* ref = clang::dyn_cast<DeclRefExpr>(s)) { 389 if (ref->getDecl() == decl) 390 ++count; 391 } 392 for (auto* c : s->children()) { 393 if (!c) 394 continue; 395 visit_stmt(c); 396 } 397 }; 398 399 visit_stmt(EnclosingCxxStatement(stmt)); 400 return count > 1; 401 } 402 403 void run(const MatchFinder::MatchResult& result) override { 404 auto* target = result.Nodes.getNodeAs<clang::DeclRefExpr>("target"); 405 auto* decl = clang::dyn_cast<clang::VarDecl>(target->getDecl()); 406 407 // Other than local variables and parameters are out-of-scope. 408 if (!decl || !decl->isLocalVarDeclOrParm()) 409 return; 410 411 auto qual_type = decl->getType(); 412 // Qualified variables are out-of-scope. They are likely not movable. 413 if (qual_type.getCanonicalType().hasQualifiers()) 414 return; 415 416 auto* type = qual_type.getTypePtr(); 417 // References and pointers are out-of-scope. 418 if (type->isReferenceType() || type->isPointerType()) 419 return; 420 421 Stmt* body = nullptr; 422 if (auto* ctor = result.Nodes.getNodeAs<LambdaExpr>("enclosing_ctor")) 423 return; // Skip constructor case for now. TBD. 424 else if (auto* func = 425 result.Nodes.getNodeAs<FunctionDecl>("enclosing_func")) 426 body = func->getBody(); 427 else if (auto* lambda = 428 result.Nodes.getNodeAs<LambdaExpr>("enclosing_lambda")) 429 body = lambda->getBody(); 430 else 431 return; 432 433 // Disable the replacement if there is a lambda that captures |decl|. 434 if (HasCapturingLambda(body, decl)) 435 return; 436 437 // Disable the replacement if the pointer to |decl| is taken in the scope. 438 if (WasPointerTaken(body, decl)) 439 return; 440 441 if (!ExtractCFGContentToMembers(body, result.Context)) 442 return; 443 444 auto* parent = parent_map_->getParentIgnoreParenCasts(target); 445 if (auto* p = clang::dyn_cast<CallExpr>(parent)) { 446 auto* callee = p->getCalleeDecl(); 447 // |callee| may be null if the CallExpr has an unresolved look up. 448 if (!callee) 449 return; 450 auto* callee_decl = clang::dyn_cast<clang::NamedDecl>(callee); 451 auto name = callee_decl->getQualifiedNameAsString(); 452 453 // Disable the replacement if it's already in std::move() or 454 // std::forward(). 455 if (name == "std::__1::move" || name == "std::__1::forward") 456 return; 457 } else if (parent->getStmtClass() == Stmt::ReturnStmtClass) { 458 // Disable the replacement if it's in a return statement. 459 return; 460 } 461 462 // If the same C++ statement contains multiple reference to the variable, 463 // don't insert std::move() to be conservative. 464 if (HasUnorderedOccurrences(decl, target)) 465 return; 466 467 bool saw_reuse = false; 468 ForEachFollowingStmts(target, [&](const Stmt* stmt) { 469 if (auto* ref = clang::dyn_cast<DeclRefExpr>(stmt)) { 470 if (ref->getDecl() == decl) { 471 saw_reuse = true; 472 return false; 473 } 474 } 475 476 // TODO: Detect Reset() and operator=() to stop the traversal. 477 return true; 478 }); 479 if (saw_reuse) 480 return; 481 482 replacements_->emplace_back( 483 *result.SourceManager, 484 result.SourceManager->getSpellingLoc(target->getLocStart()), 0, 485 "std::move("); 486 replacements_->emplace_back( 487 *result.SourceManager, 488 clang::Lexer::getLocForEndOfToken(target->getLocEnd(), 0, 489 *result.SourceManager, 490 result.Context->getLangOpts()), 491 0, ")"); 492 } 493 494 // Invokes |handler| for each Stmt that follows |target| until it reaches the 495 // end of the lifetime of the variable that |target| references. 496 // If |handler| returns false, stops following the current control flow. 497 void ForEachFollowingStmts(const DeclRefExpr* target, 498 std::function<bool(const Stmt*)> handler) { 499 auto* decl = target->getDecl(); 500 auto* block = enclosing_block_[target]; 501 502 std::set<const clang::CFGBlock*> visited; 503 std::vector<const clang::CFGBlock*> stack = {block}; 504 505 bool saw_target = false; 506 std::function<bool(const Stmt*)> visit_stmt = [&](const Stmt* s) { 507 for (auto* t : s->children()) { 508 if (!t) 509 continue; 510 511 // |t| is evaluated elsewhere if a sub-Stmt is in |top_stmt_|. 512 if (top_stmts_.find(t) != top_stmts_.end()) 513 continue; 514 515 if (!visit_stmt(t)) 516 return false; 517 } 518 519 if (!saw_target) { 520 if (s == target) 521 saw_target = true; 522 return true; 523 } 524 525 return handler(s); 526 }; 527 528 bool visited_initial_block_twice = false; 529 while (!stack.empty()) { 530 auto* b = stack.back(); 531 stack.pop_back(); 532 if (!visited.insert(b).second) { 533 if (b != block || visited_initial_block_twice) 534 continue; 535 visited_initial_block_twice = true; 536 } 537 538 bool cont = true; 539 for (auto e : *b) { 540 if (auto s = e.getAs<CFGStmt>()) { 541 if (!visit_stmt(s->getStmt())) { 542 cont = false; 543 break; 544 } 545 } else if (auto l = e.getAs<CFGLifetimeEnds>()) { 546 if (l->getVarDecl() == decl) { 547 cont = false; 548 break; 549 } 550 } 551 } 552 553 if (cont) { 554 for (auto s : b->succs()) { 555 if (!s) 556 continue; // Unreachable block. 557 stack.push_back(s); 558 } 559 } 560 } 561 } 562 563 private: 564 // Function body to CFG. 565 std::map<const Stmt*, std::unique_ptr<CFG>> cfg_cache_; 566 567 // Statement to the enclosing CFGBlock. 568 std::map<const Stmt*, const CFGBlock*> enclosing_block_; 569 570 // Stmt to its parent Stmt. 571 std::unique_ptr<clang::ParentMap> parent_map_; 572 573 // A set of Stmt that a CFGElement has it directly. 574 std::set<const Stmt*> top_stmts_; 575 576 Replacements* replacements_; 577 }; 578 579 // Remove base::AdaptCallbackForRepeating() where resulting 580 // base::RepeatingCallback is implicitly converted into base::OnceCallback. 581 // Example: 582 // // Before 583 // base::PostTask( 584 // FROM_HERE, 585 // base::AdaptCallbackForRepeating(base::BindOnce(&Foo))); 586 // base::OnceCallback<void()> cb = base::AdaptCallbackForRepeating( 587 // base::OnceBind(&Foo)); 588 // 589 // // After 590 // base::PostTask(FROM_HERE, base::BindOnce(&Foo)); 591 // base::OnceCallback<void()> cb = base::BindOnce(&Foo); 592 class AdaptCallbackForRepeatingRewriter : public MatchFinder::MatchCallback, 593 public Rewriter { 594 public: 595 explicit AdaptCallbackForRepeatingRewriter(Replacements* replacements) 596 : replacements_(replacements) {} 597 598 StatementMatcher GetMatcher() { 599 auto is_once_callback = hasType(hasCanonicalType(hasDeclaration( 600 classTemplateSpecializationDecl(hasName("::base::OnceCallback"))))); 601 auto is_repeating_callback = 602 hasType(hasCanonicalType(hasDeclaration(classTemplateSpecializationDecl( 603 hasName("::base::RepeatingCallback"))))); 604 605 auto adapt_callback_call = 606 callExpr( 607 callee(namedDecl(hasName("::base::AdaptCallbackForRepeating")))) 608 .bind("target"); 609 auto parameter_construction = 610 cxxConstructExpr(is_repeating_callback, argumentCountIs(1), 611 hasArgument(0, ignoringImplicit(adapt_callback_call))); 612 auto constructor_conversion = cxxConstructExpr( 613 is_once_callback, argumentCountIs(1), 614 hasArgument(0, ignoringImplicit(parameter_construction))); 615 return implicitCastExpr(is_once_callback, 616 hasSourceExpression(constructor_conversion)); 617 } 618 619 void run(const MatchFinder::MatchResult& result) override { 620 auto* target = result.Nodes.getNodeAs<clang::CallExpr>("target"); 621 622 auto left = clang::CharSourceRange::getTokenRange( 623 result.SourceManager->getSpellingLoc(target->getLocStart()), 624 result.SourceManager->getSpellingLoc(target->getArg(0)->getExprLoc()) 625 .getLocWithOffset(-1)); 626 627 // We use " " as replacement to work around https://crbug.com/861886. 628 replacements_->emplace_back(*result.SourceManager, left, " "); 629 auto r_paren = clang::CharSourceRange::getTokenRange( 630 result.SourceManager->getSpellingLoc(target->getRParenLoc()), 631 result.SourceManager->getSpellingLoc(target->getRParenLoc())); 632 replacements_->emplace_back(*result.SourceManager, r_paren, " "); 633 } 634 635 private: 636 Replacements* replacements_; 637 }; 638 639 llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); 640 llvm::cl::OptionCategory rewriter_category("Rewriter Options"); 641 642 llvm::cl::opt<std::string> rewriter_option( 643 "rewriter", 644 llvm::cl::desc(R"(One of the name of rewriter to apply. 645 Available rewriters are: 646 remove_unneeded_passed 647 bind_to_bind_once 648 pass_by_value 649 add_std_move 650 remove_unneeded_adapt_callback 651 The default is remove_unneeded_passed. 652 )"), 653 llvm::cl::init("remove_unneeded_passed"), 654 llvm::cl::cat(rewriter_category)); 655 656 } // namespace. 657 658 int main(int argc, const char* argv[]) { 659 llvm::InitializeNativeTarget(); 660 llvm::InitializeNativeTargetAsmParser(); 661 CommonOptionsParser options(argc, argv, rewriter_category); 662 clang::tooling::ClangTool tool(options.getCompilations(), 663 options.getSourcePathList()); 664 665 MatchFinder match_finder; 666 std::vector<clang::tooling::Replacement> replacements; 667 668 std::unique_ptr<Rewriter> rewriter; 669 if (rewriter_option == "remove_unneeded_passed") { 670 auto passed_to_move = 671 llvm::make_unique<PassedToMoveRewriter>(&replacements); 672 match_finder.addMatcher(passed_to_move->GetMatcher(), passed_to_move.get()); 673 rewriter = std::move(passed_to_move); 674 } else if (rewriter_option == "bind_to_bind_once") { 675 auto bind_once = llvm::make_unique<BindOnceRewriter>(&replacements); 676 match_finder.addMatcher(bind_once->GetMatcher(), bind_once.get()); 677 rewriter = std::move(bind_once); 678 } else if (rewriter_option == "pass_by_value") { 679 auto pass_by_value = llvm::make_unique<PassByValueRewriter>(&replacements); 680 match_finder.addMatcher(pass_by_value->GetMatcher(), pass_by_value.get()); 681 rewriter = std::move(pass_by_value); 682 } else if (rewriter_option == "add_std_move") { 683 auto add_std_move = llvm::make_unique<AddStdMoveRewriter>(&replacements); 684 match_finder.addMatcher(add_std_move->GetMatcher(), add_std_move.get()); 685 rewriter = std::move(add_std_move); 686 } else if (rewriter_option == "remove_unneeded_adapt_callback") { 687 auto remove_unneeded_adapt_callback = 688 llvm::make_unique<AdaptCallbackForRepeatingRewriter>(&replacements); 689 match_finder.addMatcher(remove_unneeded_adapt_callback->GetMatcher(), 690 remove_unneeded_adapt_callback.get()); 691 rewriter = std::move(remove_unneeded_adapt_callback); 692 } else { 693 abort(); 694 } 695 696 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = 697 clang::tooling::newFrontendActionFactory(&match_finder); 698 int result = tool.run(factory.get()); 699 if (result != 0) 700 return result; 701 702 // Serialization format is documented in tools/clang/scripts/run_tool.py 703 llvm::outs() << "==== BEGIN EDITS ====\n"; 704 for (const auto& r : replacements) { 705 std::string replacement_text = r.getReplacementText().str(); 706 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); 707 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() 708 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; 709 } 710 llvm::outs() << "==== END EDITS ====\n"; 711 712 return 0; 713 } 714