Home | History | Annotate | Download | only in Tooling
      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