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

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: Add warning to script. Created 5 years, 7 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(const std::string& input,
99 const char* from,
100 const char* 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 + strlen(from));
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 PostTaskCallback(Replacements* replacements) : replacements_(replacements) {}
120
121 virtual void run(const MatchFinder::MatchResult& result) override;
122
123 private:
124 Replacements* const replacements_;
125 };
126
127 // Refactors base::MessageLoopProxy::current() callers.
128 class CurrentProxyCallback : public MatchFinder::MatchCallback {
129 public:
130 CurrentProxyCallback(Replacements* replacements)
131 : replacements_(replacements) {}
132
133 virtual void run(const MatchFinder::MatchResult& result) override;
134
135 private:
136 Replacements* const replacements_;
137 };
138
139 // Refactors callers to base::MessageLoop::message_loop_proxy() and
140 // base::Thread::message_loop_proxy().
141 class ProxyGetterCallback : public MatchFinder::MatchCallback {
142 public:
143 ProxyGetterCallback(Replacements* replacements)
144 : replacements_(replacements) {}
145
146 virtual void run(const MatchFinder::MatchResult& result) override;
147
148 private:
149 Replacements* const replacements_;
150 };
151
152 // Rewrites variables of type MessageLoopProxy*.
153 class ProxyVariableCallback : public MatchFinder::MatchCallback {
154 public:
155 ProxyVariableCallback(Replacements* replacements)
156 : replacements_(replacements) {}
157
158 virtual void run(const MatchFinder::MatchResult& result) override;
159
160 private:
161 Replacements* const replacements_;
162 };
163
164 // Rewrites variables of type scoped_refptr<MessageLoopProxy>.
165 class RefPtrProxyVariableCallback : public MatchFinder::MatchCallback {
166 public:
167 RefPtrProxyVariableCallback(Replacements* replacements)
168 : replacements_(replacements) {}
169
170 virtual void run(const MatchFinder::MatchResult& result) override;
171
172 private:
173 Replacements* const replacements_;
174 };
175
176 // Rewrites expressions of type MessageLoopProxy*.
177 class ProxyExprCallback : public MatchFinder::MatchCallback {
178 public:
179 ProxyExprCallback(Replacements* replacements) : replacements_(replacements) {}
180
181 virtual void run(const MatchFinder::MatchResult& result) override;
182
183 private:
184 Replacements* const replacements_;
185 };
186
187 // Rewrites generic expressions involving MessageLoopProxy* or
188 // scoped_refptr<MessageLoopProxy>.
189 class GenericProxyExprCallback : public MatchFinder::MatchCallback {
190 public:
191 GenericProxyExprCallback(Replacements* replacements)
192 : replacements_(replacements) {}
193
194 virtual void run(const MatchFinder::MatchResult& result) override;
195
196 private:
197 Replacements* const replacements_;
198 };
199
200 // Rewrites functions that return scoped_refptr<base::MessageLoopProxy>.
201 class CustomProxyGetterCallback : public MatchFinder::MatchCallback {
202 public:
203 CustomProxyGetterCallback(Replacements* replacements)
204 : replacements_(replacements) {}
205
206 virtual void run(const MatchFinder::MatchResult& result) override;
207
208 private:
209 Replacements* const replacements_;
210 };
211
212 class MessageLoopRefactorer {
213 public:
214 explicit MessageLoopRefactorer(Replacements* replacements)
215 : post_callback_(replacements),
216 current_proxy_callback_(replacements),
217 proxy_getter_callback_(replacements),
218 proxy_variable_callback_(replacements),
219 proxy_expr_callback_(replacements),
220 generic_proxy_expr_callback_(replacements),
221 refptr_proxy_variable_callback_(replacements),
222 custom_proxy_getter_callback_(replacements) {}
223
224 void SetupMatchers(MatchFinder* match_finder);
225
226 private:
227 PostTaskCallback post_callback_;
228 CurrentProxyCallback current_proxy_callback_;
229 ProxyGetterCallback proxy_getter_callback_;
230 ProxyVariableCallback proxy_variable_callback_;
231 ProxyExprCallback proxy_expr_callback_;
232 GenericProxyExprCallback generic_proxy_expr_callback_;
233 RefPtrProxyVariableCallback refptr_proxy_variable_callback_;
234 CustomProxyGetterCallback custom_proxy_getter_callback_;
235 };
236
237 void MessageLoopRefactorer::SetupMatchers(MatchFinder* match_finder) {
238 auto is_message_loop = recordDecl(isSameOrDerivedFrom("base::MessageLoop"));
239 auto is_thread = recordDecl(isSameOrDerivedFrom("base::Thread"));
240 auto is_message_loop_proxy =
241 recordDecl(isSameOrDerivedFrom("base::MessageLoopProxy"));
242
243 // Matches calls to the Post*Task APIs.
244 auto post_matcher =
245 memberCallExpr(thisPointerType(is_message_loop),
246 callee(methodDecl(anyOf(
247 hasName("PostTask"), hasName("PostDelayedTask"),
248 hasName("PostNonNestableTask"),
249 hasName("PostNonNestableDelayedTask"))))).bind("call");
250
251 // Matches calls to MessageLoopProxy::current().
252 auto current_proxy_matcher =
253 callExpr(callee(methodDecl(ofClass(is_message_loop_proxy),
254 hasName("current")))).bind("call");
255
256 auto message_loop_proxy_callee =
257 callee(methodDecl(hasName("message_loop_proxy")));
258
259 // Matches calls to MessageLoop::message_loop_proxy().
260 auto loop_proxy_getter_matcher =
261 memberCallExpr(thisPointerType(is_message_loop),
262 message_loop_proxy_callee).bind("call");
263
264 // Matches calls to Thread::message_loop_proxy().
265 auto thread_proxy_getter_matcher =
266 memberCallExpr(thisPointerType(is_thread), message_loop_proxy_callee)
267 .bind("call");
268
269 // Matches variables and members pointing to a MessageLoopProxy that aren't
270 // inside template instantiations (e.g., scoped_retpr<>).
271 auto proxy_variable_matcher =
272 varDecl(hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))),
273 unless(hasAncestor(decl(anyOf(
274 recordDecl(isTemplateInstantiation()),
275 functionDecl(isTemplateInstantiation())))))).bind("var");
276 auto proxy_field_matcher =
277 fieldDecl(
278 hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))),
279 unless(hasAncestor(decl(
280 anyOf(recordDecl(isTemplateInstantiation()),
281 functionDecl(isTemplateInstantiation())))))).bind("field");
282
283 // Matches any expressions that evaluate to base::MessageLoopProxy* but
284 // aren't result from a member or function call (e.g.,
285 // MessageLoopProxy::current()).
286 auto proxy_expr_matcher =
287 expr(hasType(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))),
288 unless(anyOf(hasDescendant(callExpr()),
289 hasDescendant(memberCallExpr())))).bind("expr");
290
291 // Matches methods which return or MessageLoopProxy* scoped_refptr<*>.
292 auto proxy_method_matcher =
293 methodDecl(
294 returns(pointsTo(recordDecl(hasName("base::MessageLoopProxy")))))
295 .bind("method");
296 auto refptr_proxy_method_matcher =
297 methodDecl(returns(asString("scoped_refptr<base::MessageLoopProxy>")))
298 .bind("method");
299
300 // Matches scoped_refptr<*> variable and member declarations. Note that
301 // further matching is done in the replacement to only target
302 // scoped_refptr<base::MessageLoopProxy>.
303 auto refptr_proxy_field_matcher =
304 fieldDecl(hasType(recordDecl(hasName("::scoped_refptr")))).bind("field");
305 auto refptr_proxy_variable_matcher =
306 varDecl(hasType(recordDecl(hasName("::scoped_refptr")))).bind("var");
307 auto refptr_proxy_ref_field_matcher =
308 fieldDecl(hasType(references(recordDecl(hasName("::scoped_refptr")))))
309 .bind("field");
310 auto refptr_proxy_ref_variable_matcher =
311 varDecl(hasType(references(recordDecl(hasName("::scoped_refptr")))))
312 .bind("var");
313
314 // The following three matchers are used to rename variables. They look for
315 // expressions, constructor initializers and declaration references (i.e.,
316 // constructor initializer parameters) of the type base::MessageLoopProxy* or
317 // any scoped_refptr<>. The actual matching to
318 // scoped_refptr<base::MessageLoopProxy> happens in the callback since I
319 // couldn't come up with a reliable AST matcher for doing that here.
320
321 // Matches scoped_refptr<> which is being passed as an argument to a
322 // function.
323 auto proxy_refptr_expr_matcher =
324 expr(hasType(recordDecl(hasName("::scoped_refptr"))),
325 anyOf(hasAncestor(callExpr()), hasAncestor(memberCallExpr())))
326 .bind("expr");
327
328 auto proxy_refptr_member_expr_matcher =
329 memberExpr(hasType(recordDecl(hasName("::scoped_refptr"))))
330 .bind("member");
331
332 // Matches any constructor initializer.
333 auto ctor_proxy_expr_matcher = constructorDecl(
334 forEachConstructorInitializer(ctorInitializer().bind("ctor")));
335
336 // Matches any declaration reference to a MessageLoopProxy* or
337 // scoped_refptr<>.
338 auto proxy_decl_ref_expr_matcher =
339 declRefExpr(anyOf(hasType(recordDecl(hasName("::scoped_refptr"))),
340 hasType(pointsTo(recordDecl(
341 hasName("base::MessageLoopProxy")))))).bind("ref");
342
343 match_finder->addMatcher(current_proxy_matcher, &current_proxy_callback_);
344 match_finder->addMatcher(loop_proxy_getter_matcher, &proxy_getter_callback_);
345 match_finder->addMatcher(thread_proxy_getter_matcher,
346 &proxy_getter_callback_);
347 match_finder->addMatcher(post_matcher, &post_callback_);
348 match_finder->addMatcher(proxy_variable_matcher, &proxy_variable_callback_);
349 match_finder->addMatcher(proxy_field_matcher, &proxy_variable_callback_);
350 match_finder->addMatcher(refptr_proxy_field_matcher,
351 &refptr_proxy_variable_callback_);
352 match_finder->addMatcher(refptr_proxy_variable_matcher,
353 &refptr_proxy_variable_callback_);
354 match_finder->addMatcher(refptr_proxy_ref_field_matcher,
355 &refptr_proxy_variable_callback_);
356 match_finder->addMatcher(refptr_proxy_ref_variable_matcher,
357 &refptr_proxy_variable_callback_);
358 match_finder->addMatcher(proxy_expr_matcher, &proxy_expr_callback_);
359
360 match_finder->addMatcher(proxy_refptr_expr_matcher,
361 &generic_proxy_expr_callback_);
362 match_finder->addMatcher(ctor_proxy_expr_matcher,
363 &generic_proxy_expr_callback_);
364 match_finder->addMatcher(proxy_decl_ref_expr_matcher,
365 &generic_proxy_expr_callback_);
366 match_finder->addMatcher(proxy_refptr_member_expr_matcher,
367 &generic_proxy_expr_callback_);
368
369 match_finder->addMatcher(proxy_method_matcher,
370 &custom_proxy_getter_callback_);
371 match_finder->addMatcher(refptr_proxy_method_matcher,
372 &custom_proxy_getter_callback_);
373 }
374
375 void PostTaskCallback::run(const MatchFinder::MatchResult& result) {
376 const CXXMemberCallExpr* call =
377 result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
378 const Expr* obj = call->getImplicitObjectArgument();
379 const MemberExpr* callee = clang::dyn_cast<MemberExpr>(call->getCallee());
380
381 clang::CharSourceRange range =
382 clang::CharSourceRange::getTokenRange(callee->getSourceRange());
383 clang::CharSourceRange obj_range =
384 clang::CharSourceRange::getTokenRange(obj->getSourceRange());
385
386 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
387 result.Context->getLangOpts());
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 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
416 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()";
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 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
484 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 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
524 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 std::string text = clang::Lexer::getSourceText(range, *result.SourceManager,
547 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())
dcheng 2015/05/06 17:31:18 Are you actually generating overlapping edits, or
Sami 2015/05/07 10:37:37 They are identical in the sense that the end resul
dcheng 2015/05/26 20:35:44 I'm really surprised that you need to do this. The
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