• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
RewriterCallback(Replacements * replacements)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 
run(const MatchFinder::MatchResult & result)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 
main(int argc,const char * argv[])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