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

Side by Side 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: Removed some hacks. 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 unified diff | Download patch
OLDNEW
(Empty)
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 // This tool performs the following transformations on base::MessageLoop and
6 // related APIs:
7 //
8 // MessageLoop:
9 // - base::MessageLoop::PostTask*
10 // => base::MessageLoop::task_runner()->PostTask*()
11 //
12 // Thread:
13 // - base::Thread::message_loop_proxy()
14 // => task_runner()
15 //
16 // MessageLoopProxy:
17 // - base::MessageLoopProxy
18 // => base::SingleThreadTaskRunner
19 // - scoped_refptr<base::MessageLoopProxy>
20 // => scoped_refptr<base::SingleThreadTaskRunner>
21 // - base::MessageLoopProxy::current()
22 // => base::ThreadTaskRunnerHandle::Get()
23 // - base::MessageLoop::message_loop_proxy()
24 // => base::MessageLoop::task_runner() (done)
25 //
26 // Additionally, the tool renames variables of type MessageLoopProxy* or
27 // scoped_refptr<MessageLoopProxy> as follows:
28 // - *message_loop_proxy* => *task_runner*
29 // - *message_loop* => *task_runner*
30 // - *loop_proxy* => *task_runner*
31 // - *proxy* => *task_runner*
32 // - *loop* => *task_runner*
33 //
34
35 #include <memory>
36 #include "clang/AST/ExprCXX.h"
37 #include "clang/ASTMatchers/ASTMatchers.h"
38 #include "clang/ASTMatchers/ASTMatchFinder.h"
39 #include "clang/Basic/SourceManager.h"
40 #include "clang/Frontend/FrontendActions.h"
41 #include "clang/Lex/Lexer.h"
42 #include "clang/Tooling/CommonOptionsParser.h"
43 #include "clang/Tooling/Refactoring.h"
44 #include "clang/Tooling/Tooling.h"
45 #include "llvm/Support/CommandLine.h"
46
47 using clang::ast_matchers::MatchFinder;
48 using clang::ast_matchers::anyOf;
49 using clang::ast_matchers::asString;
50 using clang::ast_matchers::callExpr;
51 using clang::ast_matchers::callee;
52 using clang::ast_matchers::constructExpr;
53 using clang::ast_matchers::ctorInitializer;
54 using clang::ast_matchers::decl;
55 using clang::ast_matchers::declRefExpr;
56 using clang::ast_matchers::expr;
57 using clang::ast_matchers::fieldDecl;
58 using clang::ast_matchers::functionDecl;
59 using clang::ast_matchers::hasAncestor;
60 using clang::ast_matchers::hasAnyTemplateArgument;
61 using clang::ast_matchers::hasDescendant;
62 using clang::ast_matchers::hasName;
63 using clang::ast_matchers::hasType;
64 using clang::ast_matchers::isSameOrDerivedFrom;
65 using clang::ast_matchers::isTemplateInstantiation;
66 using clang::ast_matchers::memberCallExpr;
67 using clang::ast_matchers::memberExpr;
68 using clang::ast_matchers::methodDecl;
69 using clang::ast_matchers::ofClass;
70 using clang::ast_matchers::pointsTo;
71 using clang::ast_matchers::recordDecl;
72 using clang::ast_matchers::references;
73 using clang::ast_matchers::refersToType;
74 using clang::ast_matchers::returns;
75 using clang::ast_matchers::templateSpecializationType;
76 using clang::ast_matchers::thisPointerType;
77 using clang::ast_matchers::unless;
78 using clang::ast_matchers::varDecl;
79 using clang::ast_matchers::constructorDecl;
80 using clang::ast_matchers::forEachConstructorInitializer;
81
82 using clang::tooling::CommonOptionsParser;
83 using clang::tooling::Replacement;
84 using clang::tooling::Replacements;
85
86 using clang::CXXMethodDecl;
87 using clang::CXXMemberCallExpr;
88 using clang::CXXCtorInitializer;
89 using clang::CallExpr;
90 using clang::Expr;
91 using clang::DeclRefExpr;
92 using clang::FieldDecl;
93 using clang::MemberExpr;
94 using clang::VarDecl;
95
96 namespace {
97
98 std::string ReplaceFirst(llvm::StringRef input,
99 llvm::StringRef from,
100 llvm::StringRef to) {
101 size_t pos = input.find(from);
102 if (pos == std::string::npos)
103 return input;
104 return (input.substr(0, pos) + to + input.substr(pos + from.size())).str();
105 }
106
107 std::string RenameMessageLoopProxyVariable(std::string name) {
108 name = ReplaceFirst(name, "message_loop_proxy", "task_runner");
109 name = ReplaceFirst(name, "message_loop", "task_runner");
110 name = ReplaceFirst(name, "loop_proxy", "task_runner");
111 name = ReplaceFirst(name, "proxy", "task_runner");
112 name = ReplaceFirst(name, "loop", "task_runner");
113 return name;
114 }
115
116 // Handles conversion of the Post*Task APIs.
117 class PostTaskCallback : public MatchFinder::MatchCallback {
118 public:
119 explicit PostTaskCallback(Replacements* replacements)
120 : replacements_(replacements) {}
121
122 void run(const MatchFinder::MatchResult& result) override;
123
124 private:
125 Replacements* const replacements_;
126 };
127
128 // Refactors base::MessageLoopProxy::current() callers.
129 class CurrentProxyCallback : public MatchFinder::MatchCallback {
130 public:
131 explicit CurrentProxyCallback(Replacements* replacements)
132 : replacements_(replacements) {}
133
134 void run(const MatchFinder::MatchResult& result) override;
135
136 private:
137 Replacements* const replacements_;
138 };
139
140 // Refactors callers to base::MessageLoop::message_loop_proxy() and
141 // base::Thread::message_loop_proxy().
142 class ProxyGetterCallback : public MatchFinder::MatchCallback {
143 public:
144 explicit ProxyGetterCallback(Replacements* replacements)
145 : replacements_(replacements) {}
146
147 void run(const MatchFinder::MatchResult& result) override;
148
149 private:
150 Replacements* const replacements_;
151 };
152
153 // Rewrites variables of type MessageLoopProxy*.
154 class ProxyVariableCallback : public MatchFinder::MatchCallback {
155 public:
156 explicit ProxyVariableCallback(Replacements* replacements)
157 : replacements_(replacements) {}
158
159 void run(const MatchFinder::MatchResult& result) override;
160
161 private:
162 Replacements* const replacements_;
163 };
164
165 // Rewrites variables of type scoped_refptr<MessageLoopProxy>.
166 class RefPtrProxyVariableCallback : public MatchFinder::MatchCallback {
167 public:
168 explicit RefPtrProxyVariableCallback(Replacements* replacements)
169 : replacements_(replacements) {}
170
171 void run(const MatchFinder::MatchResult& result) override;
172
173 private:
174 Replacements* const replacements_;
175 };
176
177 // Rewrites expressions of type MessageLoopProxy*.
178 class ProxyExprCallback : public MatchFinder::MatchCallback {
179 public:
180 explicit ProxyExprCallback(Replacements* replacements)
181 : replacements_(replacements) {}
182
183 void run(const MatchFinder::MatchResult& result) override;
184
185 private:
186 Replacements* const replacements_;
187 };
188
189 // Rewrites generic expressions involving MessageLoopProxy* or
190 // scoped_refptr<MessageLoopProxy>.
191 class GenericProxyExprCallback : public MatchFinder::MatchCallback {
192 public:
193 explicit GenericProxyExprCallback(Replacements* replacements)
194 : replacements_(replacements) {}
195
196 void run(const MatchFinder::MatchResult& result) override;
197
198 private:
199 Replacements* const replacements_;
200 };
201
202 // Rewrites functions that return scoped_refptr<base::MessageLoopProxy>.
203 class CustomProxyGetterCallback : public MatchFinder::MatchCallback {
204 public:
205 explicit CustomProxyGetterCallback(Replacements* replacements)
206 : replacements_(replacements) {}
207
208 void run(const MatchFinder::MatchResult& result) override;
209
210 private:
211 Replacements* const replacements_;
212 };
213
214 class MessageLoopRefactorer {
215 public:
216 explicit MessageLoopRefactorer(Replacements* replacements)
217 : post_callback_(replacements),
218 current_proxy_callback_(replacements),
219 proxy_getter_callback_(replacements),
220 proxy_variable_callback_(replacements),
221 proxy_expr_callback_(replacements),
222 generic_proxy_expr_callback_(replacements),
223 refptr_proxy_variable_callback_(replacements),
224 custom_proxy_getter_callback_(replacements) {}
225
226 void SetupMatchers(MatchFinder* match_finder);
227
228 private:
229 PostTaskCallback post_callback_;
230 CurrentProxyCallback current_proxy_callback_;
231 ProxyGetterCallback proxy_getter_callback_;
232 ProxyVariableCallback proxy_variable_callback_;
233 ProxyExprCallback proxy_expr_callback_;
234 GenericProxyExprCallback generic_proxy_expr_callback_;
235 RefPtrProxyVariableCallback refptr_proxy_variable_callback_;
236 CustomProxyGetterCallback custom_proxy_getter_callback_;
237 };
238
239 void MessageLoopRefactorer::SetupMatchers(MatchFinder* match_finder) {
240 auto is_message_loop = recordDecl(isSameOrDerivedFrom("base::MessageLoop"));
241 auto is_thread = recordDecl(isSameOrDerivedFrom("base::Thread"));
242 auto is_message_loop_proxy =
243 recordDecl(isSameOrDerivedFrom("base::MessageLoopProxy"));
244
245 // Matches calls to the Post*Task APIs.
246 auto post_matcher =
247 memberCallExpr(thisPointerType(is_message_loop),
248 callee(methodDecl(anyOf(
249 hasName("PostTask"), hasName("PostDelayedTask"),
250 hasName("PostNonNestableTask"),
251 hasName("PostNonNestableDelayedTask"))))).bind("call");
252
253 // Matches calls to MessageLoopProxy::current().
254 auto current_proxy_matcher =
255 callExpr(callee(methodDecl(ofClass(is_message_loop_proxy),
256 hasName("current")))).bind("call");
257
258 auto message_loop_proxy_callee =
259 callee(methodDecl(hasName("message_loop_proxy")));
260
261 // Matches calls to MessageLoop::message_loop_proxy().
262 auto loop_proxy_getter_matcher =
263 memberCallExpr(thisPointerType(is_message_loop),
264 message_loop_proxy_callee).bind("call");
265
266 // Matches calls to Thread::message_loop_proxy().
267 auto thread_proxy_getter_matcher =
268 memberCallExpr(thisPointerType(is_thread), message_loop_proxy_callee)
269 .bind("call");
270
271 // Matches variables and members pointing to a MessageLoopProxy that aren't
272 // inside template instantiations (e.g., scoped_retpr<>).
273 auto proxy_variable_matcher =
274 varDecl(hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))),
275 unless(hasAncestor(decl(anyOf(
276 recordDecl(isTemplateInstantiation()),
277 functionDecl(isTemplateInstantiation())))))).bind("var");
278 auto proxy_field_matcher =
279 fieldDecl(
280 hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))),
281 unless(hasAncestor(decl(
282 anyOf(recordDecl(isTemplateInstantiation()),
283 functionDecl(isTemplateInstantiation())))))).bind("field");
284
285 // Matches any expressions that evaluate to base::MessageLoopProxy* but
286 // aren't result from a member or function call (e.g.,
287 // MessageLoopProxy::current()).
288 auto proxy_expr_matcher =
289 expr(hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))),
290 unless(anyOf(hasDescendant(callExpr()),
291 hasDescendant(memberCallExpr())))).bind("expr");
292
293 // Matches methods which return or MessageLoopProxy* scoped_refptr<*>.
294 auto proxy_method_matcher =
295 methodDecl(
296 returns(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))))
297 .bind("method");
298 auto refptr_proxy_method_matcher =
299 methodDecl(returns(asString("scoped_refptr<base::MessageLoopProxy>")))
300 .bind("method");
301
302 // Matches scoped_refptr<*> variable and member declarations. Note that
303 // further matching is done in the replacement to only target
304 // scoped_refptr<base::MessageLoopProxy>.
305 auto refptr_proxy_field_matcher =
306 fieldDecl(hasType(recordDecl(hasName("::scoped_refptr")))).bind("field");
307 auto refptr_proxy_variable_matcher =
308 varDecl(hasType(recordDecl(hasName("::scoped_refptr")))).bind("var");
309 auto refptr_proxy_ref_field_matcher =
310 fieldDecl(hasType(references(recordDecl(hasName("::scoped_refptr")))))
311 .bind("field");
312 auto refptr_proxy_ref_variable_matcher =
313 varDecl(hasType(references(recordDecl(hasName("::scoped_refptr")))))
314 .bind("var");
315
316 // The following three matchers are used to rename variables. They look for
317 // expressions, constructor initializers and declaration references (i.e.,
318 // constructor initializer parameters) of the type base::MessageLoopProxy* or
319 // any scoped_refptr<>. The actual matching to
320 // scoped_refptr<base::MessageLoopProxy> happens in the callback since I
321 // couldn't come up with a reliable AST matcher for doing that here.
322
323 // Matches scoped_refptr<> which is being passed as an argument to a
324 // function.
325 auto proxy_refptr_expr_matcher =
326 expr(hasType(recordDecl(hasName("::scoped_refptr"))),
327 anyOf(hasAncestor(callExpr()), hasAncestor(memberCallExpr())))
328 .bind("expr");
329
330 auto proxy_refptr_member_expr_matcher =
331 memberExpr(hasType(recordDecl(hasName("::scoped_refptr"))))
332 .bind("member");
333
334 // Matches any constructor initializer.
335 auto ctor_proxy_expr_matcher = constructorDecl(
336 forEachConstructorInitializer(ctorInitializer().bind("ctor")));
337
338 // Matches any declaration reference to a MessageLoopProxy* or
339 // scoped_refptr<>.
340 auto proxy_decl_ref_expr_matcher =
341 declRefExpr(anyOf(hasType(recordDecl(hasName("::scoped_refptr"))),
342 hasType(pointsTo(recordDecl(
343 hasName("base::MessageLoopProxy")))))).bind("ref");
344
345 match_finder->addMatcher(current_proxy_matcher, &current_proxy_callback_);
346 match_finder->addMatcher(loop_proxy_getter_matcher, &proxy_getter_callback_);
347 match_finder->addMatcher(thread_proxy_getter_matcher,
348 &proxy_getter_callback_);
349 match_finder->addMatcher(post_matcher, &post_callback_);
350 match_finder->addMatcher(proxy_variable_matcher, &proxy_variable_callback_);
351 match_finder->addMatcher(proxy_field_matcher, &proxy_variable_callback_);
352 match_finder->addMatcher(refptr_proxy_field_matcher,
353 &refptr_proxy_variable_callback_);
354 match_finder->addMatcher(refptr_proxy_variable_matcher,
355 &refptr_proxy_variable_callback_);
356 match_finder->addMatcher(refptr_proxy_ref_field_matcher,
357 &refptr_proxy_variable_callback_);
358 match_finder->addMatcher(refptr_proxy_ref_variable_matcher,
359 &refptr_proxy_variable_callback_);
360 match_finder->addMatcher(proxy_expr_matcher, &proxy_expr_callback_);
361
362 match_finder->addMatcher(proxy_refptr_expr_matcher,
363 &generic_proxy_expr_callback_);
364 match_finder->addMatcher(ctor_proxy_expr_matcher,
365 &generic_proxy_expr_callback_);
366 match_finder->addMatcher(proxy_decl_ref_expr_matcher,
367 &generic_proxy_expr_callback_);
368 match_finder->addMatcher(proxy_refptr_member_expr_matcher,
369 &generic_proxy_expr_callback_);
370
371 match_finder->addMatcher(proxy_method_matcher,
372 &custom_proxy_getter_callback_);
373 match_finder->addMatcher(refptr_proxy_method_matcher,
374 &custom_proxy_getter_callback_);
375 }
376
377 void PostTaskCallback::run(const MatchFinder::MatchResult& result) {
378 const CXXMemberCallExpr* call =
379 result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
380 const Expr* obj = call->getImplicitObjectArgument();
381 const MemberExpr* callee = clang::dyn_cast<MemberExpr>(call->getCallee());
382
383 clang::CharSourceRange range =
384 clang::CharSourceRange::getTokenRange(callee->getSourceRange());
385 clang::CharSourceRange obj_range =
386 clang::CharSourceRange::getTokenRange(obj->getSourceRange());
387
388 std::string obj_text = clang::Lexer::getSourceText(
389 obj_range, *result.SourceManager, result.Context->getLangOpts());
390 std::string method = call->getMethodDecl()->getNameInfo().getAsString();
391
392 // Rewrite the call to go through the task runner.
393 bool is_arrow = callee->isArrow();
394 std::string replacement =
395 obj_text + (is_arrow ? "->" : ".") + "task_runner()->" + method;
396
397 // Rewrite MessageLoop::current() as ThreadTaskRunnerHandle::Get().
398 if (obj_text.find("MessageLoop::current") != obj_text.npos ||
399 obj_text.find("MessageLoopForIO::current") != obj_text.npos ||
400 obj_text.find("MessageLoopForUI::current") != obj_text.npos) {
401 std::string ns = "";
402 if (obj_text.find("base::") == 0) {
403 ns = "base::";
404 }
405 replacement = ns + "ThreadTaskRunnerHandle::Get()->" + method;
406 }
407
408 replacements_->insert(Replacement(*result.SourceManager, range, replacement));
409 }
410
411 void CurrentProxyCallback::run(const MatchFinder::MatchResult& result) {
412 const CallExpr* call = result.Nodes.getNodeAs<CallExpr>("call");
413 clang::CharSourceRange range =
414 clang::CharSourceRange::getTokenRange(call->getSourceRange());
415 llvm::StringRef text = clang::Lexer::getSourceText(
416 range, *result.SourceManager, result.Context->getLangOpts());
417
418 std::string ns = "";
419 if (text.find("base::") == 0) {
420 ns = "base::";
421 }
422 std::string replacement = ns + "ThreadTaskRunnerHandle::Get()";
dcheng 2015/05/26 20:35:44 My main objection to landing this patch as-is is t
423 replacements_->insert(Replacement(*result.SourceManager, range, replacement));
424 }
425
426 void ProxyGetterCallback::run(const MatchFinder::MatchResult& result) {
427 const CXXMemberCallExpr* call =
428 result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
429 const MemberExpr* callee = clang::dyn_cast<MemberExpr>(call->getCallee());
430 clang::CharSourceRange range =
431 clang::CharSourceRange::getTokenRange(callee->getSourceRange());
432
433 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
434 result.Context->getLangOpts());
435
436 text = ReplaceFirst(text, "message_loop_proxy", "task_runner");
437 replacements_->insert(Replacement(*result.SourceManager, range, text));
438 }
439
440 void ProxyVariableCallback::run(const MatchFinder::MatchResult& result) {
441 const VarDecl* var = result.Nodes.getNodeAs<VarDecl>("var");
442 const FieldDecl* field = result.Nodes.getNodeAs<FieldDecl>("field");
443 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
444 var ? var->getSourceRange() : field->getSourceRange());
445
446 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
447 result.Context->getLangOpts());
448
449 // Change the type of the pointee.
450 text = ReplaceFirst(text, "MessageLoopProxy", "SingleThreadTaskRunner");
451
452 // Rename the pointer variable too.
453 text = RenameMessageLoopProxyVariable(text);
454
455 replacements_->insert(Replacement(*result.SourceManager, range, text));
456 }
457
458 void RefPtrProxyVariableCallback::run(const MatchFinder::MatchResult& result) {
459 const VarDecl* var = result.Nodes.getNodeAs<VarDecl>("var");
460 const FieldDecl* field = result.Nodes.getNodeAs<FieldDecl>("field");
461 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
462 var ? var->getSourceRange() : field->getSourceRange());
463
464 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
465 result.Context->getLangOpts());
466 if (text.find("MessageLoopProxy") == text.npos)
467 return;
468
469 // Change the type of the pointee.
470 text = ReplaceFirst(text, "MessageLoopProxy", "SingleThreadTaskRunner");
471
472 // Rename the refptr variable too.
473 text = RenameMessageLoopProxyVariable(text);
474
475 replacements_->insert(Replacement(*result.SourceManager, range, text));
476 }
477
478 void ProxyExprCallback::run(const MatchFinder::MatchResult& result) {
479 const Expr* expr = result.Nodes.getNodeAs<Expr>("expr");
480 clang::CharSourceRange range =
481 clang::CharSourceRange::getTokenRange(expr->getSourceRange());
482
483 llvm::StringRef text = clang::Lexer::getSourceText(
484 range, *result.SourceManager, result.Context->getLangOpts());
485
486 std::string replacement = RenameMessageLoopProxyVariable(text);
487 if (replacement != text) {
488 replacements_->insert(
489 Replacement(*result.SourceManager, range, replacement));
490 }
491 }
492
493 void GenericProxyExprCallback::run(const MatchFinder::MatchResult& result) {
494 const Expr* expr = result.Nodes.getNodeAs<Expr>("expr");
495 const CXXCtorInitializer* ctor =
496 result.Nodes.getNodeAs<CXXCtorInitializer>("ctor");
497 const DeclRefExpr* ref = result.Nodes.getNodeAs<DeclRefExpr>("ref");
498 const MemberExpr* member = result.Nodes.getNodeAs<MemberExpr>("member");
499 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(
500 expr ? expr->getSourceRange() : ref ? ref->getSourceRange()
501 : member ? member->getSourceRange()
502 : ctor->getSourceRange());
503
504 std::string type;
505 if (expr) {
506 type = expr->getType().getAsString();
507 } else if (ref) {
508 type = ref->getType().getAsString();
509 } else if (member) {
510 type = member->getType().getAsString();
511 } else {
512 // Ignore base class constructors.
513 if (!ctor->getMember())
514 return;
515 type = ctor->getMember()->getType().getAsString();
516 }
517
518 // Ignore unrelated scoped_refptr<>s.
519 if (type.find("scoped_refptr<base::MessageLoopProxy>") == type.npos &&
520 type.find("base::MessageLoopProxy *") == type.npos)
521 return;
522
523 llvm::StringRef text = clang::Lexer::getSourceText(
524 range, *result.SourceManager, result.Context->getLangOpts());
525 std::string replacement = RenameMessageLoopProxyVariable(text);
526
527 // For field initializers, also try renaming the initializing value.
528 if (ctor) {
529 replacement = RenameMessageLoopProxyVariable(replacement);
530 // Hack: rename any static getter because the renaming of the field will
531 // conflict the edit that replaces the getter.
532 replacement = ReplaceFirst(replacement, "base::MessageLoopProxy::current()",
533 "base::ThreadTaskRunnerHandle::Get()");
534 }
535
536 if (replacement != text) {
537 replacements_->insert(
538 Replacement(*result.SourceManager, range, replacement));
539 }
540 }
541
542 void CustomProxyGetterCallback::run(const MatchFinder::MatchResult& result) {
543 const CXXMethodDecl* method = result.Nodes.getNodeAs<CXXMethodDecl>("method");
544 clang::CharSourceRange range =
545 clang::CharSourceRange::getTokenRange(method->getReturnTypeSourceRange());
546 llvm::StringRef text = clang::Lexer::getSourceText(
547 range, *result.SourceManager, result.Context->getLangOpts());
548
549 std::string replacement =
550 ReplaceFirst(text, "MessageLoopProxy", "SingleThreadTaskRunner");
551 if (replacement != text) {
552 replacements_->insert(
553 Replacement(*result.SourceManager, range, replacement));
554 }
555 }
556
557 } // namespace
558
559 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
560
561 int main(int argc, const char* argv[]) {
562 llvm::cl::OptionCategory category("MessageLoop refactoring tool");
563 CommonOptionsParser options(argc, argv, category);
564 clang::tooling::ClangTool tool(options.getCompilations(),
565 options.getSourcePathList());
566
567 Replacements replacements;
568 MessageLoopRefactorer refactorer(&replacements);
569 MatchFinder match_finder;
570 refactorer.SetupMatchers(&match_finder);
571
572 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory =
573 clang::tooling::newFrontendActionFactory(&match_finder);
574 int result = tool.run(frontend_factory.get());
575 if (result != 0)
576 return result;
577
578 // Each replacement line should have the following format:
579 // r:<file path>:<offset>:<length>:<replacement text>
580 // Only the <replacement text> field can contain embedded ":" characters.
581 // TODO(dcheng): Use a more clever serialization. Ideally we'd use the YAML
582 // serialization and then use clang-apply-replacements, but that would require
583 // copying and pasting a larger amount of boilerplate for all Chrome clang
584 // tools.
585 llvm::outs() << "==== BEGIN EDITS ====\n";
586 unsigned prev_end = 0;
587 for (const auto& r : replacements) {
588 // Discard overlapping edits.
589 if (prev_end > r.getOffset())
590 continue;
591 prev_end = r.getOffset() + r.getLength();
592 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset()
593 << ":::" << r.getLength() << ":::" << r.getReplacementText()
594 << "\n";
595 }
596 llvm::outs() << "==== END EDITS ====\n";
597
598 return 0;
599 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698