Chromium Code Reviews| 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 |