Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Unified Diff: tools/clang/refactor_message_loop/RefactorMessageLoop.cpp

Issue 1010073002: clang: Add a tool for MessageLoop refactoring (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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, &current_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;
+}
« no previous file with comments | « tools/clang/refactor_message_loop/CMakeLists.txt ('k') | tools/clang/refactor_message_loop/tests/test-expected.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698