summaryrefslogtreecommitdiffstats
path: root/include/clang/Tooling/RefactoringCallbacks.h
blob: 2137e0035d629380aaef819c49c95b66c7cd71e7 (plain)
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
140
//===--- RefactoringCallbacks.h - Structural query framework ----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  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