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

Unified Diff: tools/clang/BindMigrate/TransformPostTask.cpp

Issue 7886056: Clang plugin that rewrites PostTask(_, NewRunnableMethod(...)) to PostTask(_, base::Bind(...)); (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: break into files and make saner Created 9 years, 3 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 side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698