Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 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 | |||
| 34 | namespace clang { | ||
| 35 | namespace tooling { | ||
| 36 | |||
| 37 | /// Base class for RefactoringCallbacks. | ||
| 38 | /// | ||
| 39 | /// Collects \c tooling::Replacements while running. | ||
| 40 | class RefactoringCallback : public ast_matchers::MatchFinder::MatchCallback { | ||
| 41 | public: | ||
| 42 | RefactoringCallback(); | ||
| 43 | Replacements &getReplacements(); | ||
| 44 | |||
| 45 | protected: | ||
| 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. | ||
| 53 | class ASTMatchRefactorer { | ||
| 54 | public: | ||
| 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 | |||
| 69 | private: | ||
| 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. | ||
| 78 | class ReplaceStmtWithText : public RefactoringCallback { | ||
| 79 | public: | ||
| 80 | ReplaceStmtWithText(StringRef FromId, StringRef ToText); | ||
| 81 | void run(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
| 82 | |||
| 83 | private: | ||
| 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 "$". | ||
| 94 | class ReplaceNodeWithTemplate : public RefactoringCallback { | ||
| 95 | public: | ||
| 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 | |||
| 100 | private: | ||
| 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. | ||
| 113 | class ReplaceStmtWithStmt : public RefactoringCallback { | ||
| 114 | public: | ||
| 115 | ReplaceStmtWithStmt(StringRef FromId, StringRef ToId); | ||
| 116 | void run(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
| 117 | |||
| 118 | private: | ||
| 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. | ||
| 126 | class ReplaceIfStmtWithItsBody : public RefactoringCallback { | ||
| 127 | public: | ||
| 128 | ReplaceIfStmtWithItsBody(StringRef Id, bool PickTrueBranch); | ||
| 129 | void run(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
| 130 | |||
| 131 | private: | ||
| 132 | std::string Id; | ||
| 133 | const bool PickTrueBranch; | ||
| 134 | }; | ||
| 135 | |||
| 136 | } // end namespace tooling | ||
| 137 | } // end namespace clang | ||
| 138 | |||
| 139 | #endif |