1// Copyright 2016 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4// 5// This file containts a clang tool to update base::Bind() callers: 6// * Remove unneeded scoped_refptr<>::get() on method binding. 7 8#include <assert.h> 9#include <algorithm> 10#include <memory> 11#include <string> 12 13#include "clang/AST/ASTContext.h" 14#include "clang/ASTMatchers/ASTMatchers.h" 15#include "clang/ASTMatchers/ASTMatchersMacros.h" 16#include "clang/ASTMatchers/ASTMatchFinder.h" 17#include "clang/Basic/SourceManager.h" 18#include "clang/Frontend/FrontendActions.h" 19#include "clang/Lex/Lexer.h" 20#include "clang/Tooling/CommonOptionsParser.h" 21#include "clang/Tooling/Refactoring.h" 22#include "clang/Tooling/Tooling.h" 23#include "llvm/Support/CommandLine.h" 24#include "llvm/Support/TargetSelect.h" 25 26using namespace clang::ast_matchers; 27using clang::tooling::CommonOptionsParser; 28using Replacements = std::vector<clang::tooling::Replacement>; 29 30namespace { 31 32// Remove unneeded scoped_refptr<>::get on a receivers of method bind. 33// Example: 34// // Before 35// scoped_refptr<Foo> foo; 36// base::Bind(&Foo::Bar, foo.get()); 37// 38// // After 39// scoped_refptr<Foo> foo; 40// base::Bind(&Foo::Bar, foo); 41// 42class ScopedRefptrGetRewriter : public MatchFinder::MatchCallback { 43 public: 44 explicit ScopedRefptrGetRewriter(Replacements* replacements) 45 : replacements_(replacements) {} 46 47 StatementMatcher GetMatcher() { 48 auto is_bind_call = callee(namedDecl(hasName("::base::Bind"))); 49 auto is_method_bind = hasArgument(0, hasType(memberPointerType())); 50 auto is_raw_pointer_receiver = hasArgument(1, hasType(pointerType())); 51 auto is_scoped_refptr_get_call = 52 cxxMemberCallExpr(thisPointerType(namedDecl(hasName("scoped_refptr"))), 53 callee(namedDecl(hasName("get")))); 54 return callExpr(is_bind_call, is_method_bind, is_raw_pointer_receiver, 55 hasArgument(1, is_scoped_refptr_get_call), 56 hasArgument(1, stmt().bind("target"))); 57 } 58 59 void run(const MatchFinder::MatchResult& result) override { 60 auto* target = result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("target"); 61 auto* member = llvm::cast<clang::MemberExpr>(target->getCallee()); 62 assert(target && member && "Unexpected match! No Expr captured!"); 63 auto range = clang::CharSourceRange::getTokenRange( 64 result.SourceManager->getSpellingLoc(member->getOperatorLoc()), 65 result.SourceManager->getSpellingLoc(target->getLocEnd())); 66 67 replacements_->emplace_back(*result.SourceManager, range, ""); 68 } 69 70 private: 71 Replacements* replacements_; 72}; 73 74llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); 75 76} // namespace. 77 78int main(int argc, const char* argv[]) { 79 llvm::InitializeNativeTarget(); 80 llvm::InitializeNativeTargetAsmParser(); 81 llvm::cl::OptionCategory category( 82 "Remove raw pointer on the receiver of Bind() target"); 83 CommonOptionsParser options(argc, argv, category); 84 clang::tooling::ClangTool tool(options.getCompilations(), 85 options.getSourcePathList()); 86 87 MatchFinder match_finder; 88 std::vector<clang::tooling::Replacement> replacements; 89 90 91 ScopedRefptrGetRewriter scoped_refptr_rewriter(&replacements); 92 match_finder.addMatcher(scoped_refptr_rewriter.GetMatcher(), 93 &scoped_refptr_rewriter); 94 95 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = 96 clang::tooling::newFrontendActionFactory(&match_finder); 97 int result = tool.run(factory.get()); 98 if (result != 0) 99 return result; 100 101 // Serialization format is documented in tools/clang/scripts/run_tool.py 102 llvm::outs() << "==== BEGIN EDITS ====\n"; 103 for (const auto& r : replacements) { 104 std::string replacement_text = r.getReplacementText().str(); 105 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); 106 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() 107 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; 108 } 109 llvm::outs() << "==== END EDITS ====\n"; 110 111 return 0; 112} 113