Home | History | Annotate | Download | only in pass_to_move
      1 // Copyright 2015 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 // Clang tool to change calls to scoper::Pass() to just use std::move().
      6 
      7 #include <memory>
      8 #include <string>
      9 
     10 #include "clang/AST/ASTContext.h"
     11 #include "clang/ASTMatchers/ASTMatchFinder.h"
     12 #include "clang/ASTMatchers/ASTMatchers.h"
     13 #include "clang/ASTMatchers/ASTMatchersMacros.h"
     14 #include "clang/Basic/SourceManager.h"
     15 #include "clang/Frontend/FrontendActions.h"
     16 #include "clang/Lex/Lexer.h"
     17 #include "clang/Tooling/CommonOptionsParser.h"
     18 #include "clang/Tooling/Refactoring.h"
     19 #include "clang/Tooling/Tooling.h"
     20 #include "llvm/Support/CommandLine.h"
     21 #include "llvm/Support/TargetSelect.h"
     22 
     23 using namespace clang::ast_matchers;
     24 using clang::tooling::CommonOptionsParser;
     25 using clang::tooling::Replacement;
     26 using clang::tooling::Replacements;
     27 using llvm::StringRef;
     28 
     29 namespace {
     30 
     31 class RewriterCallback : public MatchFinder::MatchCallback {
     32  public:
     33   explicit RewriterCallback(Replacements* replacements)
     34       : replacements_(replacements) {}
     35   virtual void run(const MatchFinder::MatchResult& result) override;
     36 
     37  private:
     38   Replacements* const replacements_;
     39 };
     40 
     41 void RewriterCallback::run(const MatchFinder::MatchResult& result) {
     42   const clang::CXXMemberCallExpr* call_expr =
     43       result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("expr");
     44   const clang::MemberExpr* callee =
     45       clang::dyn_cast<clang::MemberExpr>(call_expr->getCallee());
     46   const bool is_arrow = callee->isArrow();
     47   const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
     48 
     49   const char kMoveRefText[] = "std::move(";
     50   const char kMovePtrText[] = "std::move(*";
     51 
     52   auto err = replacements_->add(
     53       Replacement(*result.SourceManager,
     54                   result.SourceManager->getSpellingLoc(arg->getLocStart()), 0,
     55                   is_arrow ? kMovePtrText : kMoveRefText));
     56   assert(!err);
     57 
     58   // Delete everything but the closing parentheses from the original call to
     59   // Pass(): the closing parantheses is left to match up with the parantheses
     60   // just inserted with std::move.
     61   err = replacements_->add(Replacement(
     62       *result.SourceManager,
     63       clang::CharSourceRange::getCharRange(
     64           result.SourceManager->getSpellingLoc(callee->getOperatorLoc()),
     65           result.SourceManager->getSpellingLoc(call_expr->getRParenLoc())),
     66       ""));
     67   assert(!err);
     68 }
     69 
     70 }  // namespace
     71 
     72 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
     73 
     74 int main(int argc, const char* argv[]) {
     75   // TODO(dcheng): Clang tooling should do this itself.
     76   // http://llvm.org/bugs/show_bug.cgi?id=21627
     77   llvm::InitializeNativeTarget();
     78   llvm::InitializeNativeTargetAsmParser();
     79   llvm::cl::OptionCategory category(
     80       "C++11 modernization: change scoped::Pass() to std::move()");
     81   CommonOptionsParser options(argc, argv, category);
     82   clang::tooling::ClangTool tool(options.getCompilations(),
     83                                  options.getSourcePathList());
     84 
     85   MatchFinder match_finder;
     86   Replacements replacements;
     87 
     88   auto pass_matcher = id(
     89       "expr",
     90       cxxMemberCallExpr(
     91           argumentCountIs(0),
     92           callee(functionDecl(hasName("Pass"), returns(rValueReferenceType()))),
     93           on(id("arg", expr()))));
     94   RewriterCallback callback(&replacements);
     95   match_finder.addMatcher(pass_matcher, &callback);
     96 
     97   std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
     98       clang::tooling::newFrontendActionFactory(&match_finder);
     99   int result = tool.run(factory.get());
    100   if (result != 0)
    101     return result;
    102 
    103   // Serialization format is documented in tools/clang/scripts/run_tool.py
    104   llvm::outs() << "==== BEGIN EDITS ====\n";
    105   for (const auto& r : replacements) {
    106     std::string replacement_text = r.getReplacementText().str();
    107     std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
    108     llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset()
    109                  << ":::" << r.getLength() << ":::" << replacement_text << "\n";
    110   }
    111   llvm::outs() << "==== END EDITS ====\n";
    112 
    113   return 0;
    114 }
    115