OLD | NEW |
---|---|
(Empty) | |
1 #include "TransformPostTask.h" | |
2 | |
3 #include "clang/AST/ASTContext.h" | |
4 #include "clang/AST/Expr.h" | |
5 #include "clang/AST/ExprCXX.h" | |
6 #include "clang/Rewrite/Rewriter.h" | |
7 | |
8 #include "DiagnosticEmitter.h" | |
9 | |
10 using namespace std; | |
11 | |
12 namespace clang { | |
13 | |
14 const char TransformPostTask::kPostTaskName[] = "PostTask"; | |
15 const char TransformPostTask::kNewRunnableMethodName[] = "NewRunnableMethod"; | |
16 | |
17 TransformPostTask::TransformPostTask(ASTContext* context, Rewriter* rewriter, | |
18 DiagnosticEmitter* emitter) | |
19 : context_(context), rewriter_(rewriter), error_emitter_(emitter) { | |
20 interesting_classes_.insert("MessageLoop"); | |
21 interesting_classes_.insert("MessageLoopProxy"); | |
22 } | |
23 | |
24 bool TransformPostTask::TraverseStmt(Stmt *statement) { | |
25 // Catch the MessageLoop and MessageLoopProxy calls. | |
26 if (CXXMemberCallExpr* mce = dyn_cast_or_null<CXXMemberCallExpr>(statement)) { | |
27 if (IsPostTaskExpr(mce)) { | |
28 if (mce->getNumArgs() < 2) { | |
29 error_emitter_->EmitError( | |
30 statement->getLocStart(), | |
31 "PostTask with less than 2 args?! Inconceivable!"); | |
32 return false; | |
33 } | |
34 MaybeRewriteNewRunnableMethod(mce->getArgs()[1]); | |
35 } | |
36 } | |
37 return RecursiveASTVisitor<TransformPostTask>::TraverseStmt(statement); | |
38 } | |
39 | |
40 bool TransformPostTask::IsPostTaskExpr(CXXMemberCallExpr* call) { | |
41 CXXMethodDecl* method_decl = call->getMethodDecl()->getCanonicalDecl(); | |
42 // TODO(ajwong): Maybe just look up all the target Decls and compare those | |
43 // directly. Look at src/v8/tools/gcmole.cc for how to find the Decl. | |
44 if (kPostTaskName == method_decl->getNameAsString()) { | |
Nico
2011/09/16 03:00:54
Nit: with early returns, this gets less nested. It
awong
2011/09/16 10:24:32
Done.
| |
45 string classname = method_decl->getThisType(*context_) | |
46 .getBaseTypeIdentifier()->getName(); | |
47 | |
48 if (!interesting_classes_.empty()) { | |
49 return true; | |
50 } | |
51 } | |
52 return false; | |
53 } | |
54 | |
55 bool TransformPostTask::MaybeRewriteNewRunnableMethod(Expr* post_task_arg) { | |
56 // Skip any implicit conversions and any casts. We wantz the function!! | |
57 post_task_arg = post_task_arg->IgnoreImplicit()->IgnoreParenCasts(); | |
58 | |
59 // Strip implicit casts. | |
60 if (ImplicitCastExpr* ice = dyn_cast<ImplicitCastExpr>(post_task_arg)) { | |
61 return MaybeRewriteNewRunnableMethod(ice->getSubExpr()); | |
62 } | |
63 | |
64 CallExpr* ce = dyn_cast<CallExpr>(post_task_arg); | |
65 if (!ce) return false; | |
66 FunctionDecl *fd = ce->getDirectCallee(); | |
67 if (!fd) return false; | |
68 if (kNewRunnableMethodName != | |
69 fd->getNameInfo().getName().getAsIdentifierInfo()->getName()) | |
70 return false; | |
71 | |
72 if (ce->getNumArgs() < 2) { | |
73 error_emitter_->EmitWarning( | |
74 post_task_arg->getLocStart(), | |
75 "NewRunnableMethod with less than 2 args?! Inconceivable!"); | |
76 return false; | |
77 } | |
78 | |
79 // Okay, here's where it gets fun. We need to | |
80 // (1) replace the NRM identifier text with base::Bind. | |
81 // (2) Swap positions of the first two arguments. | |
82 | |
83 // NewRunnableMethod -> base::Bind | |
84 rewriter_->ReplaceText(ce->getCallee()->getSourceRange(), "base::Bind"); | |
85 | |
86 // Swap the argument order. | |
87 Expr* arg1 = ce->getArgs()[0]; | |
88 Expr* arg2 = ce->getArgs()[1]; | |
89 bool failure = rewriter_->ReplaceStmt(arg1, arg2); | |
90 failure |= rewriter_->ReplaceStmt(arg2, arg1); | |
91 | |
92 // TODO(ajwong): | |
93 // (3) Check the RunnableMethodTraits for the second argument, and | |
94 // wrap base::Unretained() if it is declared with | |
95 // DISABLE_RUNNABLE_METHOD_REFCOUNT. | |
96 return failure; | |
97 } | |
98 | |
99 } // namespace clang | |
OLD | NEW |