| Index: tools/clang/refactor_message_loop/RefactorMessageLoop.cpp | 
| diff --git a/tools/clang/refactor_message_loop/RefactorMessageLoop.cpp b/tools/clang/refactor_message_loop/RefactorMessageLoop.cpp | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..2c6b19dc5af1b6c370d1071cf39e651516ec56c2 | 
| --- /dev/null | 
| +++ b/tools/clang/refactor_message_loop/RefactorMessageLoop.cpp | 
| @@ -0,0 +1,599 @@ | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| +// | 
| +// This tool performs the following transformations on base::MessageLoop and | 
| +// related APIs: | 
| +// | 
| +// MessageLoop: | 
| +// - base::MessageLoop::PostTask* | 
| +//   => base::MessageLoop::task_runner()->PostTask*() | 
| +// | 
| +// Thread: | 
| +// - base::Thread::message_loop_proxy() | 
| +//   => task_runner() | 
| +// | 
| +// MessageLoopProxy: | 
| +// - base::MessageLoopProxy | 
| +//   => base::SingleThreadTaskRunner | 
| +// - scoped_refptr<base::MessageLoopProxy> | 
| +//   => scoped_refptr<base::SingleThreadTaskRunner> | 
| +// - base::MessageLoopProxy::current() | 
| +//   => base::ThreadTaskRunnerHandle::Get() | 
| +// - base::MessageLoop::message_loop_proxy() | 
| +//   => base::MessageLoop::task_runner() (done) | 
| +// | 
| +// Additionally, the tool renames variables of type MessageLoopProxy* or | 
| +// scoped_refptr<MessageLoopProxy> as follows: | 
| +// - *message_loop_proxy* => *task_runner* | 
| +// - *message_loop* => *task_runner* | 
| +// - *loop_proxy* => *task_runner* | 
| +// - *proxy* => *task_runner* | 
| +// - *loop* => *task_runner* | 
| +// | 
| + | 
| +#include <memory> | 
| +#include "clang/AST/ExprCXX.h" | 
| +#include "clang/ASTMatchers/ASTMatchers.h" | 
| +#include "clang/ASTMatchers/ASTMatchFinder.h" | 
| +#include "clang/Basic/SourceManager.h" | 
| +#include "clang/Frontend/FrontendActions.h" | 
| +#include "clang/Lex/Lexer.h" | 
| +#include "clang/Tooling/CommonOptionsParser.h" | 
| +#include "clang/Tooling/Refactoring.h" | 
| +#include "clang/Tooling/Tooling.h" | 
| +#include "llvm/Support/CommandLine.h" | 
| + | 
| +using clang::ast_matchers::MatchFinder; | 
| +using clang::ast_matchers::anyOf; | 
| +using clang::ast_matchers::asString; | 
| +using clang::ast_matchers::callExpr; | 
| +using clang::ast_matchers::callee; | 
| +using clang::ast_matchers::constructExpr; | 
| +using clang::ast_matchers::ctorInitializer; | 
| +using clang::ast_matchers::decl; | 
| +using clang::ast_matchers::declRefExpr; | 
| +using clang::ast_matchers::expr; | 
| +using clang::ast_matchers::fieldDecl; | 
| +using clang::ast_matchers::functionDecl; | 
| +using clang::ast_matchers::hasAncestor; | 
| +using clang::ast_matchers::hasAnyTemplateArgument; | 
| +using clang::ast_matchers::hasDescendant; | 
| +using clang::ast_matchers::hasName; | 
| +using clang::ast_matchers::hasType; | 
| +using clang::ast_matchers::isSameOrDerivedFrom; | 
| +using clang::ast_matchers::isTemplateInstantiation; | 
| +using clang::ast_matchers::memberCallExpr; | 
| +using clang::ast_matchers::memberExpr; | 
| +using clang::ast_matchers::methodDecl; | 
| +using clang::ast_matchers::ofClass; | 
| +using clang::ast_matchers::pointsTo; | 
| +using clang::ast_matchers::recordDecl; | 
| +using clang::ast_matchers::references; | 
| +using clang::ast_matchers::refersToType; | 
| +using clang::ast_matchers::returns; | 
| +using clang::ast_matchers::templateSpecializationType; | 
| +using clang::ast_matchers::thisPointerType; | 
| +using clang::ast_matchers::unless; | 
| +using clang::ast_matchers::varDecl; | 
| +using clang::ast_matchers::constructorDecl; | 
| +using clang::ast_matchers::forEachConstructorInitializer; | 
| + | 
| +using clang::tooling::CommonOptionsParser; | 
| +using clang::tooling::Replacement; | 
| +using clang::tooling::Replacements; | 
| + | 
| +using clang::CXXMethodDecl; | 
| +using clang::CXXMemberCallExpr; | 
| +using clang::CXXCtorInitializer; | 
| +using clang::CallExpr; | 
| +using clang::Expr; | 
| +using clang::DeclRefExpr; | 
| +using clang::FieldDecl; | 
| +using clang::MemberExpr; | 
| +using clang::VarDecl; | 
| + | 
| +namespace { | 
| + | 
| +std::string ReplaceFirst(llvm::StringRef input, | 
| +                         llvm::StringRef from, | 
| +                         llvm::StringRef to) { | 
| +  size_t pos = input.find(from); | 
| +  if (pos == std::string::npos) | 
| +    return input; | 
| +  return (input.substr(0, pos) + to + input.substr(pos + from.size())).str(); | 
| +} | 
| + | 
| +std::string RenameMessageLoopProxyVariable(std::string name) { | 
| +  name = ReplaceFirst(name, "message_loop_proxy", "task_runner"); | 
| +  name = ReplaceFirst(name, "message_loop", "task_runner"); | 
| +  name = ReplaceFirst(name, "loop_proxy", "task_runner"); | 
| +  name = ReplaceFirst(name, "proxy", "task_runner"); | 
| +  name = ReplaceFirst(name, "loop", "task_runner"); | 
| +  return name; | 
| +} | 
| + | 
| +// Handles conversion of the Post*Task APIs. | 
| +class PostTaskCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit PostTaskCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Refactors base::MessageLoopProxy::current() callers. | 
| +class CurrentProxyCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit CurrentProxyCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Refactors callers to base::MessageLoop::message_loop_proxy() and | 
| +// base::Thread::message_loop_proxy(). | 
| +class ProxyGetterCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit ProxyGetterCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Rewrites variables of type MessageLoopProxy*. | 
| +class ProxyVariableCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit ProxyVariableCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Rewrites variables of type scoped_refptr<MessageLoopProxy>. | 
| +class RefPtrProxyVariableCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit RefPtrProxyVariableCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Rewrites expressions of type MessageLoopProxy*. | 
| +class ProxyExprCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit ProxyExprCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Rewrites generic expressions involving MessageLoopProxy* or | 
| +// scoped_refptr<MessageLoopProxy>. | 
| +class GenericProxyExprCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit GenericProxyExprCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +// Rewrites functions that return scoped_refptr<base::MessageLoopProxy>. | 
| +class CustomProxyGetterCallback : public MatchFinder::MatchCallback { | 
| + public: | 
| +  explicit CustomProxyGetterCallback(Replacements* replacements) | 
| +      : replacements_(replacements) {} | 
| + | 
| +  void run(const MatchFinder::MatchResult& result) override; | 
| + | 
| + private: | 
| +  Replacements* const replacements_; | 
| +}; | 
| + | 
| +class MessageLoopRefactorer { | 
| + public: | 
| +  explicit MessageLoopRefactorer(Replacements* replacements) | 
| +      : post_callback_(replacements), | 
| +        current_proxy_callback_(replacements), | 
| +        proxy_getter_callback_(replacements), | 
| +        proxy_variable_callback_(replacements), | 
| +        proxy_expr_callback_(replacements), | 
| +        generic_proxy_expr_callback_(replacements), | 
| +        refptr_proxy_variable_callback_(replacements), | 
| +        custom_proxy_getter_callback_(replacements) {} | 
| + | 
| +  void SetupMatchers(MatchFinder* match_finder); | 
| + | 
| + private: | 
| +  PostTaskCallback post_callback_; | 
| +  CurrentProxyCallback current_proxy_callback_; | 
| +  ProxyGetterCallback proxy_getter_callback_; | 
| +  ProxyVariableCallback proxy_variable_callback_; | 
| +  ProxyExprCallback proxy_expr_callback_; | 
| +  GenericProxyExprCallback generic_proxy_expr_callback_; | 
| +  RefPtrProxyVariableCallback refptr_proxy_variable_callback_; | 
| +  CustomProxyGetterCallback custom_proxy_getter_callback_; | 
| +}; | 
| + | 
| +void MessageLoopRefactorer::SetupMatchers(MatchFinder* match_finder) { | 
| +  auto is_message_loop = recordDecl(isSameOrDerivedFrom("base::MessageLoop")); | 
| +  auto is_thread = recordDecl(isSameOrDerivedFrom("base::Thread")); | 
| +  auto is_message_loop_proxy = | 
| +      recordDecl(isSameOrDerivedFrom("base::MessageLoopProxy")); | 
| + | 
| +  // Matches calls to the Post*Task APIs. | 
| +  auto post_matcher = | 
| +      memberCallExpr(thisPointerType(is_message_loop), | 
| +                     callee(methodDecl(anyOf( | 
| +                         hasName("PostTask"), hasName("PostDelayedTask"), | 
| +                         hasName("PostNonNestableTask"), | 
| +                         hasName("PostNonNestableDelayedTask"))))).bind("call"); | 
| + | 
| +  // Matches calls to MessageLoopProxy::current(). | 
| +  auto current_proxy_matcher = | 
| +      callExpr(callee(methodDecl(ofClass(is_message_loop_proxy), | 
| +                                 hasName("current")))).bind("call"); | 
| + | 
| +  auto message_loop_proxy_callee = | 
| +      callee(methodDecl(hasName("message_loop_proxy"))); | 
| + | 
| +  // Matches calls to MessageLoop::message_loop_proxy(). | 
| +  auto loop_proxy_getter_matcher = | 
| +      memberCallExpr(thisPointerType(is_message_loop), | 
| +                     message_loop_proxy_callee).bind("call"); | 
| + | 
| +  // Matches calls to Thread::message_loop_proxy(). | 
| +  auto thread_proxy_getter_matcher = | 
| +      memberCallExpr(thisPointerType(is_thread), message_loop_proxy_callee) | 
| +          .bind("call"); | 
| + | 
| +  // Matches variables and members pointing to a MessageLoopProxy that aren't | 
| +  // inside template instantiations (e.g., scoped_retpr<>). | 
| +  auto proxy_variable_matcher = | 
| +      varDecl(hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))), | 
| +              unless(hasAncestor(decl(anyOf( | 
| +                  recordDecl(isTemplateInstantiation()), | 
| +                  functionDecl(isTemplateInstantiation())))))).bind("var"); | 
| +  auto proxy_field_matcher = | 
| +      fieldDecl( | 
| +          hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))), | 
| +          unless(hasAncestor(decl( | 
| +              anyOf(recordDecl(isTemplateInstantiation()), | 
| +                    functionDecl(isTemplateInstantiation())))))).bind("field"); | 
| + | 
| +  // Matches any expressions that evaluate to base::MessageLoopProxy* but | 
| +  // aren't result from a member or function call (e.g., | 
| +  // MessageLoopProxy::current()). | 
| +  auto proxy_expr_matcher = | 
| +      expr(hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))), | 
| +           unless(anyOf(hasDescendant(callExpr()), | 
| +                        hasDescendant(memberCallExpr())))).bind("expr"); | 
| + | 
| +  // Matches methods which return or MessageLoopProxy* scoped_refptr<*>. | 
| +  auto proxy_method_matcher = | 
| +      methodDecl( | 
| +          returns(pointsTo(recordDecl(hasName("base::MessageLoopProxy"))))) | 
| +          .bind("method"); | 
| +  auto refptr_proxy_method_matcher = | 
| +      methodDecl(returns(asString("scoped_refptr<base::MessageLoopProxy>"))) | 
| +          .bind("method"); | 
| + | 
| +  // Matches scoped_refptr<*> variable and member declarations. Note that | 
| +  // further matching is done in the replacement to only target | 
| +  // scoped_refptr<base::MessageLoopProxy>. | 
| +  auto refptr_proxy_field_matcher = | 
| +      fieldDecl(hasType(recordDecl(hasName("::scoped_refptr")))).bind("field"); | 
| +  auto refptr_proxy_variable_matcher = | 
| +      varDecl(hasType(recordDecl(hasName("::scoped_refptr")))).bind("var"); | 
| +  auto refptr_proxy_ref_field_matcher = | 
| +      fieldDecl(hasType(references(recordDecl(hasName("::scoped_refptr"))))) | 
| +          .bind("field"); | 
| +  auto refptr_proxy_ref_variable_matcher = | 
| +      varDecl(hasType(references(recordDecl(hasName("::scoped_refptr"))))) | 
| +          .bind("var"); | 
| + | 
| +  // The following three matchers are used to rename variables. They look for | 
| +  // expressions, constructor initializers and declaration references (i.e., | 
| +  // constructor initializer parameters) of the type base::MessageLoopProxy* or | 
| +  // any scoped_refptr<>. The actual matching to | 
| +  // scoped_refptr<base::MessageLoopProxy> happens in the callback since I | 
| +  // couldn't come up with a reliable AST matcher for doing that here. | 
| + | 
| +  // Matches scoped_refptr<> which is being passed as an argument to a | 
| +  // function. | 
| +  auto proxy_refptr_expr_matcher = | 
| +      expr(hasType(recordDecl(hasName("::scoped_refptr"))), | 
| +           anyOf(hasAncestor(callExpr()), hasAncestor(memberCallExpr()))) | 
| +          .bind("expr"); | 
| + | 
| +  auto proxy_refptr_member_expr_matcher = | 
| +      memberExpr(hasType(recordDecl(hasName("::scoped_refptr")))) | 
| +          .bind("member"); | 
| + | 
| +  // Matches any constructor initializer. | 
| +  auto ctor_proxy_expr_matcher = constructorDecl( | 
| +      forEachConstructorInitializer(ctorInitializer().bind("ctor"))); | 
| + | 
| +  // Matches any declaration reference to a MessageLoopProxy* or | 
| +  // scoped_refptr<>. | 
| +  auto proxy_decl_ref_expr_matcher = | 
| +      declRefExpr(anyOf(hasType(recordDecl(hasName("::scoped_refptr"))), | 
| +                        hasType(pointsTo(recordDecl( | 
| +                            hasName("base::MessageLoopProxy")))))).bind("ref"); | 
| + | 
| +  match_finder->addMatcher(current_proxy_matcher, ¤t_proxy_callback_); | 
| +  match_finder->addMatcher(loop_proxy_getter_matcher, &proxy_getter_callback_); | 
| +  match_finder->addMatcher(thread_proxy_getter_matcher, | 
| +                           &proxy_getter_callback_); | 
| +  match_finder->addMatcher(post_matcher, &post_callback_); | 
| +  match_finder->addMatcher(proxy_variable_matcher, &proxy_variable_callback_); | 
| +  match_finder->addMatcher(proxy_field_matcher, &proxy_variable_callback_); | 
| +  match_finder->addMatcher(refptr_proxy_field_matcher, | 
| +                           &refptr_proxy_variable_callback_); | 
| +  match_finder->addMatcher(refptr_proxy_variable_matcher, | 
| +                           &refptr_proxy_variable_callback_); | 
| +  match_finder->addMatcher(refptr_proxy_ref_field_matcher, | 
| +                           &refptr_proxy_variable_callback_); | 
| +  match_finder->addMatcher(refptr_proxy_ref_variable_matcher, | 
| +                           &refptr_proxy_variable_callback_); | 
| +  match_finder->addMatcher(proxy_expr_matcher, &proxy_expr_callback_); | 
| + | 
| +  match_finder->addMatcher(proxy_refptr_expr_matcher, | 
| +                           &generic_proxy_expr_callback_); | 
| +  match_finder->addMatcher(ctor_proxy_expr_matcher, | 
| +                           &generic_proxy_expr_callback_); | 
| +  match_finder->addMatcher(proxy_decl_ref_expr_matcher, | 
| +                           &generic_proxy_expr_callback_); | 
| +  match_finder->addMatcher(proxy_refptr_member_expr_matcher, | 
| +                           &generic_proxy_expr_callback_); | 
| + | 
| +  match_finder->addMatcher(proxy_method_matcher, | 
| +                           &custom_proxy_getter_callback_); | 
| +  match_finder->addMatcher(refptr_proxy_method_matcher, | 
| +                           &custom_proxy_getter_callback_); | 
| +} | 
| + | 
| +void PostTaskCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const CXXMemberCallExpr* call = | 
| +      result.Nodes.getNodeAs<CXXMemberCallExpr>("call"); | 
| +  const Expr* obj = call->getImplicitObjectArgument(); | 
| +  const MemberExpr* callee = clang::dyn_cast<MemberExpr>(call->getCallee()); | 
| + | 
| +  clang::CharSourceRange range = | 
| +      clang::CharSourceRange::getTokenRange(callee->getSourceRange()); | 
| +  clang::CharSourceRange obj_range = | 
| +      clang::CharSourceRange::getTokenRange(obj->getSourceRange()); | 
| + | 
| +  std::string obj_text = clang::Lexer::getSourceText( | 
| +      obj_range, *result.SourceManager, result.Context->getLangOpts()); | 
| +  std::string method = call->getMethodDecl()->getNameInfo().getAsString(); | 
| + | 
| +  // Rewrite the call to go through the task runner. | 
| +  bool is_arrow = callee->isArrow(); | 
| +  std::string replacement = | 
| +      obj_text + (is_arrow ? "->" : ".") + "task_runner()->" + method; | 
| + | 
| +  // Rewrite MessageLoop::current() as ThreadTaskRunnerHandle::Get(). | 
| +  if (obj_text.find("MessageLoop::current") != obj_text.npos || | 
| +      obj_text.find("MessageLoopForIO::current") != obj_text.npos || | 
| +      obj_text.find("MessageLoopForUI::current") != obj_text.npos) { | 
| +    std::string ns = ""; | 
| +    if (obj_text.find("base::") == 0) { | 
| +      ns = "base::"; | 
| +    } | 
| +    replacement = ns + "ThreadTaskRunnerHandle::Get()->" + method; | 
| +  } | 
| + | 
| +  replacements_->insert(Replacement(*result.SourceManager, range, replacement)); | 
| +} | 
| + | 
| +void CurrentProxyCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const CallExpr* call = result.Nodes.getNodeAs<CallExpr>("call"); | 
| +  clang::CharSourceRange range = | 
| +      clang::CharSourceRange::getTokenRange(call->getSourceRange()); | 
| +  llvm::StringRef text = clang::Lexer::getSourceText( | 
| +      range, *result.SourceManager, result.Context->getLangOpts()); | 
| + | 
| +  std::string ns = ""; | 
| +  if (text.find("base::") == 0) { | 
| +    ns = "base::"; | 
| +  } | 
| +  std::string replacement = ns + "ThreadTaskRunnerHandle::Get()"; | 
| +  replacements_->insert(Replacement(*result.SourceManager, range, replacement)); | 
| +} | 
| + | 
| +void ProxyGetterCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const CXXMemberCallExpr* call = | 
| +      result.Nodes.getNodeAs<CXXMemberCallExpr>("call"); | 
| +  const MemberExpr* callee = clang::dyn_cast<MemberExpr>(call->getCallee()); | 
| +  clang::CharSourceRange range = | 
| +      clang::CharSourceRange::getTokenRange(callee->getSourceRange()); | 
| + | 
| +  std::string text = clang::Lexer::getSourceText(range, *result.SourceManager, | 
| +                                                 result.Context->getLangOpts()); | 
| + | 
| +  text = ReplaceFirst(text, "message_loop_proxy", "task_runner"); | 
| +  replacements_->insert(Replacement(*result.SourceManager, range, text)); | 
| +} | 
| + | 
| +void ProxyVariableCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const VarDecl* var = result.Nodes.getNodeAs<VarDecl>("var"); | 
| +  const FieldDecl* field = result.Nodes.getNodeAs<FieldDecl>("field"); | 
| +  clang::CharSourceRange range = clang::CharSourceRange::getTokenRange( | 
| +      var ? var->getSourceRange() : field->getSourceRange()); | 
| + | 
| +  std::string text = clang::Lexer::getSourceText(range, *result.SourceManager, | 
| +                                                 result.Context->getLangOpts()); | 
| + | 
| +  // Change the type of the pointee. | 
| +  text = ReplaceFirst(text, "MessageLoopProxy", "SingleThreadTaskRunner"); | 
| + | 
| +  // Rename the pointer variable too. | 
| +  text = RenameMessageLoopProxyVariable(text); | 
| + | 
| +  replacements_->insert(Replacement(*result.SourceManager, range, text)); | 
| +} | 
| + | 
| +void RefPtrProxyVariableCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const VarDecl* var = result.Nodes.getNodeAs<VarDecl>("var"); | 
| +  const FieldDecl* field = result.Nodes.getNodeAs<FieldDecl>("field"); | 
| +  clang::CharSourceRange range = clang::CharSourceRange::getTokenRange( | 
| +      var ? var->getSourceRange() : field->getSourceRange()); | 
| + | 
| +  std::string text = clang::Lexer::getSourceText(range, *result.SourceManager, | 
| +                                                 result.Context->getLangOpts()); | 
| +  if (text.find("MessageLoopProxy") == text.npos) | 
| +    return; | 
| + | 
| +  // Change the type of the pointee. | 
| +  text = ReplaceFirst(text, "MessageLoopProxy", "SingleThreadTaskRunner"); | 
| + | 
| +  // Rename the refptr variable too. | 
| +  text = RenameMessageLoopProxyVariable(text); | 
| + | 
| +  replacements_->insert(Replacement(*result.SourceManager, range, text)); | 
| +} | 
| + | 
| +void ProxyExprCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const Expr* expr = result.Nodes.getNodeAs<Expr>("expr"); | 
| +  clang::CharSourceRange range = | 
| +      clang::CharSourceRange::getTokenRange(expr->getSourceRange()); | 
| + | 
| +  llvm::StringRef text = clang::Lexer::getSourceText( | 
| +      range, *result.SourceManager, result.Context->getLangOpts()); | 
| + | 
| +  std::string replacement = RenameMessageLoopProxyVariable(text); | 
| +  if (replacement != text) { | 
| +    replacements_->insert( | 
| +        Replacement(*result.SourceManager, range, replacement)); | 
| +  } | 
| +} | 
| + | 
| +void GenericProxyExprCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const Expr* expr = result.Nodes.getNodeAs<Expr>("expr"); | 
| +  const CXXCtorInitializer* ctor = | 
| +      result.Nodes.getNodeAs<CXXCtorInitializer>("ctor"); | 
| +  const DeclRefExpr* ref = result.Nodes.getNodeAs<DeclRefExpr>("ref"); | 
| +  const MemberExpr* member = result.Nodes.getNodeAs<MemberExpr>("member"); | 
| +  clang::CharSourceRange range = clang::CharSourceRange::getTokenRange( | 
| +      expr ? expr->getSourceRange() : ref ? ref->getSourceRange() | 
| +                                          : member ? member->getSourceRange() | 
| +                                                   : ctor->getSourceRange()); | 
| + | 
| +  std::string type; | 
| +  if (expr) { | 
| +    type = expr->getType().getAsString(); | 
| +  } else if (ref) { | 
| +    type = ref->getType().getAsString(); | 
| +  } else if (member) { | 
| +    type = member->getType().getAsString(); | 
| +  } else { | 
| +    // Ignore base class constructors. | 
| +    if (!ctor->getMember()) | 
| +      return; | 
| +    type = ctor->getMember()->getType().getAsString(); | 
| +  } | 
| + | 
| +  // Ignore unrelated scoped_refptr<>s. | 
| +  if (type.find("scoped_refptr<base::MessageLoopProxy>") == type.npos && | 
| +      type.find("base::MessageLoopProxy *") == type.npos) | 
| +    return; | 
| + | 
| +  llvm::StringRef text = clang::Lexer::getSourceText( | 
| +      range, *result.SourceManager, result.Context->getLangOpts()); | 
| +  std::string replacement = RenameMessageLoopProxyVariable(text); | 
| + | 
| +  // For field initializers, also try renaming the initializing value. | 
| +  if (ctor) { | 
| +    replacement = RenameMessageLoopProxyVariable(replacement); | 
| +    // Hack: rename any static getter because the renaming of the field will | 
| +    // conflict the edit that replaces the getter. | 
| +    replacement = ReplaceFirst(replacement, "base::MessageLoopProxy::current()", | 
| +                               "base::ThreadTaskRunnerHandle::Get()"); | 
| +  } | 
| + | 
| +  if (replacement != text) { | 
| +    replacements_->insert( | 
| +        Replacement(*result.SourceManager, range, replacement)); | 
| +  } | 
| +} | 
| + | 
| +void CustomProxyGetterCallback::run(const MatchFinder::MatchResult& result) { | 
| +  const CXXMethodDecl* method = result.Nodes.getNodeAs<CXXMethodDecl>("method"); | 
| +  clang::CharSourceRange range = | 
| +      clang::CharSourceRange::getTokenRange(method->getReturnTypeSourceRange()); | 
| +  llvm::StringRef text = clang::Lexer::getSourceText( | 
| +      range, *result.SourceManager, result.Context->getLangOpts()); | 
| + | 
| +  std::string replacement = | 
| +      ReplaceFirst(text, "MessageLoopProxy", "SingleThreadTaskRunner"); | 
| +  if (replacement != text) { | 
| +    replacements_->insert( | 
| +        Replacement(*result.SourceManager, range, replacement)); | 
| +  } | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); | 
| + | 
| +int main(int argc, const char* argv[]) { | 
| +  llvm::cl::OptionCategory category("MessageLoop refactoring tool"); | 
| +  CommonOptionsParser options(argc, argv, category); | 
| +  clang::tooling::ClangTool tool(options.getCompilations(), | 
| +                                 options.getSourcePathList()); | 
| + | 
| +  Replacements replacements; | 
| +  MessageLoopRefactorer refactorer(&replacements); | 
| +  MatchFinder match_finder; | 
| +  refactorer.SetupMatchers(&match_finder); | 
| + | 
| +  std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory = | 
| +      clang::tooling::newFrontendActionFactory(&match_finder); | 
| +  int result = tool.run(frontend_factory.get()); | 
| +  if (result != 0) | 
| +    return result; | 
| + | 
| +  // Each replacement line should have the following format: | 
| +  // r:<file path>:<offset>:<length>:<replacement text> | 
| +  // Only the <replacement text> field can contain embedded ":" characters. | 
| +  // TODO(dcheng): Use a more clever serialization. Ideally we'd use the YAML | 
| +  // serialization and then use clang-apply-replacements, but that would require | 
| +  // copying and pasting a larger amount of boilerplate for all Chrome clang | 
| +  // tools. | 
| +  llvm::outs() << "==== BEGIN EDITS ====\n"; | 
| +  unsigned prev_end = 0; | 
| +  for (const auto& r : replacements) { | 
| +    // Discard overlapping edits. | 
| +    if (prev_end > r.getOffset()) | 
| +      continue; | 
| +    prev_end = r.getOffset() + r.getLength(); | 
| +    llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() | 
| +                 << ":::" << r.getLength() << ":::" << r.getReplacementText() | 
| +                 << "\n"; | 
| +  } | 
| +  llvm::outs() << "==== END EDITS ====\n"; | 
| + | 
| +  return 0; | 
| +} | 
|  |