1// Copyright (c) 2013 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 implements a Clang tool to rewrite all instances of scoped_array<T> to 6// scoped_ptr<T[]>. The former is being deprecated in favor of the latter, to 7// allow for an eventual transition from scoped_ptr to unique_ptr. 8 9#include "clang/AST/ASTContext.h" 10#include "clang/ASTMatchers/ASTMatchers.h" 11#include "clang/ASTMatchers/ASTMatchFinder.h" 12#include "clang/Basic/SourceManager.h" 13#include "clang/Frontend/FrontendActions.h" 14#include "clang/Lex/Lexer.h" 15#include "clang/Tooling/CommonOptionsParser.h" 16#include "clang/Tooling/Refactoring.h" 17#include "clang/Tooling/Tooling.h" 18#include "llvm/Support/CommandLine.h" 19 20using clang::ast_matchers::MatchFinder; 21using clang::ast_matchers::hasDeclaration; 22using clang::ast_matchers::hasName; 23using clang::ast_matchers::id; 24using clang::ast_matchers::loc; 25using clang::ast_matchers::qualType; 26using clang::ast_matchers::recordDecl; 27using clang::tooling::CommonOptionsParser; 28using clang::tooling::Replacement; 29using clang::tooling::Replacements; 30using llvm::StringRef; 31 32namespace { 33 34class RewriterCallback : public MatchFinder::MatchCallback { 35 public: 36 RewriterCallback(Replacements* replacements) : replacements_(replacements) {} 37 virtual void run(const MatchFinder::MatchResult& result) LLVM_OVERRIDE; 38 39 private: 40 Replacements* const replacements_; 41}; 42 43void RewriterCallback::run(const MatchFinder::MatchResult& result) { 44 const clang::TypeLoc type_location = 45 *result.Nodes.getNodeAs<clang::TypeLoc>("loc"); 46 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange( 47 result.SourceManager->getSpellingLoc(type_location.getLocStart()), 48 result.SourceManager->getSpellingLoc(type_location.getLocEnd())); 49 // TODO(dcheng): Log an error? 50 if (!range.isValid()) 51 return; 52 std::string replacement_text = clang::Lexer::getSourceText( 53 range, *result.SourceManager, result.Context->getLangOpts()); 54 // TODO(dcheng): Log errors? 55 if (!StringRef(replacement_text).startswith("scoped_array<") || 56 !StringRef(replacement_text).endswith(">")) 57 return; 58 replacement_text.replace(strlen("scoped_"), strlen("array"), "ptr"); 59 replacement_text.insert(replacement_text.size() - 1, "[]"); 60 replacements_->insert( 61 Replacement(*result.SourceManager, range, replacement_text)); 62} 63 64} // namespace 65 66static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); 67 68int main(int argc, const char* argv[]) { 69 CommonOptionsParser options(argc, argv); 70 clang::tooling::ClangTool tool(options.getCompilations(), 71 options.getSourcePathList()); 72 73 Replacements replacements; 74 RewriterCallback callback(&replacements); 75 MatchFinder match_finder; 76 match_finder.addMatcher( 77 id("loc", 78 loc(qualType(hasDeclaration(recordDecl(hasName("::scoped_array")))))), 79 &callback); 80 81 int result = 82 tool.run(clang::tooling::newFrontendActionFactory(&match_finder)); 83 if (result != 0) 84 return result; 85 86 // Serialization format is documented in tools/clang/scripts/run_tool.py 87 llvm::outs() << "==== BEGIN EDITS ====\n"; 88 for (Replacements::const_iterator it = replacements.begin(); 89 it != replacements.end(); ++it) { 90 llvm::outs() << "r:" << it->getFilePath() << ":" << it->getOffset() << ":" 91 << it->getLength() << ":" << it->getReplacementText() << "\n"; 92 } 93 llvm::outs() << "==== END EDITS ====\n"; 94 95 return 0; 96} 97