Chromium Code Reviews| Index: tools/clang/BindMigrate/TransformPostTask.cpp |
| diff --git a/tools/clang/BindMigrate/TransformPostTask.cpp b/tools/clang/BindMigrate/TransformPostTask.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d7d491aa2aa71672c89ae6bc9c046f0b54ac55aa |
| --- /dev/null |
| +++ b/tools/clang/BindMigrate/TransformPostTask.cpp |
| @@ -0,0 +1,99 @@ |
| +#include "TransformPostTask.h" |
| + |
| +#include "clang/AST/ASTContext.h" |
| +#include "clang/AST/Expr.h" |
| +#include "clang/AST/ExprCXX.h" |
| +#include "clang/Rewrite/Rewriter.h" |
| + |
| +#include "DiagnosticEmitter.h" |
| + |
| +using namespace std; |
| + |
| +namespace clang { |
| + |
| +const char TransformPostTask::kPostTaskName[] = "PostTask"; |
| +const char TransformPostTask::kNewRunnableMethodName[] = "NewRunnableMethod"; |
| + |
| +TransformPostTask::TransformPostTask(ASTContext* context, Rewriter* rewriter, |
| + DiagnosticEmitter* emitter) |
| + : context_(context), rewriter_(rewriter), error_emitter_(emitter) { |
| + interesting_classes_.insert("MessageLoop"); |
| + interesting_classes_.insert("MessageLoopProxy"); |
| +} |
| + |
| +bool TransformPostTask::TraverseStmt(Stmt *statement) { |
| + // Catch the MessageLoop and MessageLoopProxy calls. |
| + if (CXXMemberCallExpr* mce = dyn_cast_or_null<CXXMemberCallExpr>(statement)) { |
| + if (IsPostTaskExpr(mce)) { |
| + if (mce->getNumArgs() < 2) { |
| + error_emitter_->EmitError( |
| + statement->getLocStart(), |
| + "PostTask with less than 2 args?! Inconceivable!"); |
| + return false; |
| + } |
| + MaybeRewriteNewRunnableMethod(mce->getArgs()[1]); |
| + } |
| + } |
| + return RecursiveASTVisitor<TransformPostTask>::TraverseStmt(statement); |
| +} |
| + |
| +bool TransformPostTask::IsPostTaskExpr(CXXMemberCallExpr* call) { |
| + CXXMethodDecl* method_decl = call->getMethodDecl()->getCanonicalDecl(); |
| + // TODO(ajwong): Maybe just look up all the target Decls and compare those |
| + // directly. Look at src/v8/tools/gcmole.cc for how to find the Decl. |
| + 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.
|
| + string classname = method_decl->getThisType(*context_) |
| + .getBaseTypeIdentifier()->getName(); |
| + |
| + if (!interesting_classes_.empty()) { |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +bool TransformPostTask::MaybeRewriteNewRunnableMethod(Expr* post_task_arg) { |
| + // Skip any implicit conversions and any casts. We wantz the function!! |
| + post_task_arg = post_task_arg->IgnoreImplicit()->IgnoreParenCasts(); |
| + |
| + // Strip implicit casts. |
| + if (ImplicitCastExpr* ice = dyn_cast<ImplicitCastExpr>(post_task_arg)) { |
| + return MaybeRewriteNewRunnableMethod(ice->getSubExpr()); |
| + } |
| + |
| + CallExpr* ce = dyn_cast<CallExpr>(post_task_arg); |
| + if (!ce) return false; |
| + FunctionDecl *fd = ce->getDirectCallee(); |
| + if (!fd) return false; |
| + if (kNewRunnableMethodName != |
| + fd->getNameInfo().getName().getAsIdentifierInfo()->getName()) |
| + return false; |
| + |
| + if (ce->getNumArgs() < 2) { |
| + error_emitter_->EmitWarning( |
| + post_task_arg->getLocStart(), |
| + "NewRunnableMethod with less than 2 args?! Inconceivable!"); |
| + return false; |
| + } |
| + |
| + // Okay, here's where it gets fun. We need to |
| + // (1) replace the NRM identifier text with base::Bind. |
| + // (2) Swap positions of the first two arguments. |
| + |
| + // NewRunnableMethod -> base::Bind |
| + rewriter_->ReplaceText(ce->getCallee()->getSourceRange(), "base::Bind"); |
| + |
| + // Swap the argument order. |
| + Expr* arg1 = ce->getArgs()[0]; |
| + Expr* arg2 = ce->getArgs()[1]; |
| + bool failure = rewriter_->ReplaceStmt(arg1, arg2); |
| + failure |= rewriter_->ReplaceStmt(arg2, arg1); |
| + |
| + // TODO(ajwong): |
| + // (3) Check the RunnableMethodTraits for the second argument, and |
| + // wrap base::Unretained() if it is declared with |
| + // DISABLE_RUNNABLE_METHOD_REFCOUNT. |
| + return failure; |
| +} |
| + |
| +} // namespace clang |