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