reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
//===--- RefactoringCallbacks.h - Structural query framework ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  Provides callbacks to make common kinds of refactorings easy.
//
//  The general idea is to construct a matcher expression that describes a
//  subtree match on the AST and then replace the corresponding source code
//  either by some specific text or some other AST node.
//
//  Example:
//  int main(int argc, char **argv) {
//    ClangTool Tool(argc, argv);
//    MatchFinder Finder;
//    ReplaceStmtWithText Callback("integer", "42");
//    Finder.AddMatcher(id("integer", expression(integerLiteral())), Callback);
//    return Tool.run(newFrontendActionFactory(&Finder));
//  }
//
//  This will replace all integer literals with "42".
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H
#define LLVM_CLANG_TOOLING_REFACTORINGCALLBACKS_H

#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Refactoring.h"

namespace clang {
namespace tooling {

/// Base class for RefactoringCallbacks.
///
/// Collects \c tooling::Replacements while running.
class RefactoringCallback : public ast_matchers::MatchFinder::MatchCallback {
public:
  RefactoringCallback();
  Replacements &getReplacements();

protected:
  Replacements Replace;
};

/// Adaptor between \c ast_matchers::MatchFinder and \c
/// tooling::RefactoringTool.
///
/// Runs AST matchers and stores the \c tooling::Replacements in a map.
class ASTMatchRefactorer {
public:
  explicit ASTMatchRefactorer(
    std::map<std::string, Replacements> &FileToReplaces);

  template <typename T>
  void addMatcher(const T &Matcher, RefactoringCallback *Callback) {
    MatchFinder.addMatcher(Matcher, Callback);
    Callbacks.push_back(Callback);
  }

  void addDynamicMatcher(const ast_matchers::internal::DynTypedMatcher &Matcher,
                         RefactoringCallback *Callback);

  std::unique_ptr<ASTConsumer> newASTConsumer();

private:
  friend class RefactoringASTConsumer;
  std::vector<RefactoringCallback *> Callbacks;
  ast_matchers::MatchFinder MatchFinder;
  std::map<std::string, Replacements> &FileToReplaces;
};

/// Replace the text of the statement bound to \c FromId with the text in
/// \c ToText.
class ReplaceStmtWithText : public RefactoringCallback {
public:
  ReplaceStmtWithText(StringRef FromId, StringRef ToText);
  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;

private:
  std::string FromId;
  std::string ToText;
};

/// Replace the text of an AST node bound to \c FromId with the result of
/// evaluating the template in \c ToTemplate.
///
/// Expressions of the form ${NodeName} in \c ToTemplate will be
/// replaced by the text of the node bound to ${NodeName}. The string
/// "$$" will be replaced by "$".
class ReplaceNodeWithTemplate : public RefactoringCallback {
public:
  static llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>>
  create(StringRef FromId, StringRef ToTemplate);
  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;

private:
  struct TemplateElement {
    enum { Literal, Identifier } Type;
    std::string Value;
  };
  ReplaceNodeWithTemplate(llvm::StringRef FromId,
                          std::vector<TemplateElement> Template);
  std::string FromId;
  std::vector<TemplateElement> Template;
};

/// Replace the text of the statement bound to \c FromId with the text of
/// the statement bound to \c ToId.
class ReplaceStmtWithStmt : public RefactoringCallback {
public:
  ReplaceStmtWithStmt(StringRef FromId, StringRef ToId);
  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;

private:
  std::string FromId;
  std::string ToId;
};

/// Replace an if-statement bound to \c Id with the outdented text of its
/// body, choosing the consequent or the alternative based on whether
/// \c PickTrueBranch is true.
class ReplaceIfStmtWithItsBody : public RefactoringCallback {
public:
  ReplaceIfStmtWithItsBody(StringRef Id, bool PickTrueBranch);
  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;

private:
  std::string Id;
  const bool PickTrueBranch;
};

} // end namespace tooling
} // end namespace clang

#endif