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 |