RefactoringCallbacks.h revision 360660
1//===--- RefactoringCallbacks.h - Structural query framework ----*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// Provides callbacks to make common kinds of refactorings easy. 10// 11// The general idea is to construct a matcher expression that describes a 12// subtree match on the AST and then replace the corresponding source code 13// either by some specific text or some other AST node. 14// 15// Example: 16// int main(int argc, char **argv) { 17// ClangTool Tool(argc, argv); 18// MatchFinder Finder; 19// ReplaceStmtWithText Callback("integer", "42"); 20// Finder.AddMatcher(id("integer", expression(integerLiteral())), Callback); 21// return Tool.run(newFrontendActionFactory(&Finder)); 22// } 23// 24// This will replace all integer literals with "42". 25// 26//===----------------------------------------------------------------------===// 27 28#ifndef LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H 29#define LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H 30 31#include "clang/ASTMatchers/ASTMatchFinder.h" 32#include "clang/Tooling/Refactoring.h" 33 34namespace clang { 35namespace tooling { 36 37/// Base class for RefactoringCallbacks. 38/// 39/// Collects \c tooling::Replacements while running. 40class RefactoringCallback : public ast_matchers::MatchFinder::MatchCallback { 41public: 42 RefactoringCallback(); 43 Replacements &getReplacements(); 44 45protected: 46 Replacements Replace; 47}; 48 49/// Adaptor between \c ast_matchers::MatchFinder and \c 50/// tooling::RefactoringTool. 51/// 52/// Runs AST matchers and stores the \c tooling::Replacements in a map. 53class ASTMatchRefactorer { 54public: 55 explicit ASTMatchRefactorer( 56 std::map<std::string, Replacements> &FileToReplaces); 57 58 template <typename T> 59 void addMatcher(const T &Matcher, RefactoringCallback *Callback) { 60 MatchFinder.addMatcher(Matcher, Callback); 61 Callbacks.push_back(Callback); 62 } 63 64 void addDynamicMatcher(const ast_matchers::internal::DynTypedMatcher &Matcher, 65 RefactoringCallback *Callback); 66 67 std::unique_ptr<ASTConsumer> newASTConsumer(); 68 69private: 70 friend class RefactoringASTConsumer; 71 std::vector<RefactoringCallback *> Callbacks; 72 ast_matchers::MatchFinder MatchFinder; 73 std::map<std::string, Replacements> &FileToReplaces; 74}; 75 76/// Replace the text of the statement bound to \c FromId with the text in 77/// \c ToText. 78class ReplaceStmtWithText : public RefactoringCallback { 79public: 80 ReplaceStmtWithText(StringRef FromId, StringRef ToText); 81 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 82 83private: 84 std::string FromId; 85 std::string ToText; 86}; 87 88/// Replace the text of an AST node bound to \c FromId with the result of 89/// evaluating the template in \c ToTemplate. 90/// 91/// Expressions of the form ${NodeName} in \c ToTemplate will be 92/// replaced by the text of the node bound to ${NodeName}. The string 93/// "$$" will be replaced by "$". 94class ReplaceNodeWithTemplate : public RefactoringCallback { 95public: 96 static llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>> 97 create(StringRef FromId, StringRef ToTemplate); 98 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 99 100private: 101 struct TemplateElement { 102 enum { Literal, Identifier } Type; 103 std::string Value; 104 }; 105 ReplaceNodeWithTemplate(llvm::StringRef FromId, 106 std::vector<TemplateElement> Template); 107 std::string FromId; 108 std::vector<TemplateElement> Template; 109}; 110 111/// Replace the text of the statement bound to \c FromId with the text of 112/// the statement bound to \c ToId. 113class ReplaceStmtWithStmt : public RefactoringCallback { 114public: 115 ReplaceStmtWithStmt(StringRef FromId, StringRef ToId); 116 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 117 118private: 119 std::string FromId; 120 std::string ToId; 121}; 122 123/// Replace an if-statement bound to \c Id with the outdented text of its 124/// body, choosing the consequent or the alternative based on whether 125/// \c PickTrueBranch is true. 126class ReplaceIfStmtWithItsBody : public RefactoringCallback { 127public: 128 ReplaceIfStmtWithItsBody(StringRef Id, bool PickTrueBranch); 129 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 130 131private: 132 std::string Id; 133 const bool PickTrueBranch; 134}; 135 136} // end namespace tooling 137} // end namespace clang 138 139#endif 140