summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/cpp11-migrate/Core/Transform.h
blob: 264b59526a78f29489665be0005c018c50b8f92c (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//===-- cpp11-migrate/Transform.h - Transform Base Class Def'n --*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file provides the definition for the base Transform class from
/// which all transforms must subclass.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H

#include <string>
#include <vector>
#include "IncludeExcludeInfo.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/Timer.h"

// For RewriterContainer
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
////


/// \brief Description of the riskiness of actions that can be taken by
/// transforms.
enum RiskLevel {
  /// Transformations that will not change semantics.
  RL_Safe,

  /// Transformations that might change semantics.
  RL_Reasonable,

  /// Transformations that are likely to change semantics.
  RL_Risky
};

// Forward declarations
namespace clang {
namespace tooling {
class CompilationDatabase;
} // namespace tooling
} // namespace clang

/// \brief The key is the path of a file, which is mapped to a
/// buffer with the possibly modified contents of that file.
typedef std::map<std::string, std::string> FileContentsByPath;

/// \brief In \p Results place copies of the buffers resulting from applying
/// all rewrites represented by \p Rewrite.
///
/// \p Results is made up of pairs {filename, buffer contents}. Pairs are
/// simply appended to \p Results.
void collectResults(clang::Rewriter &Rewrite,
                    const FileContentsByPath &InputStates,
                    FileContentsByPath &Results);

/// \brief Class for containing a Rewriter instance and all of
/// its lifetime dependencies.
///
/// Subclasses of Transform using RefactoringTools will need to create
/// Rewriters in order to apply Replacements and get the resulting buffer.
/// Rewriter requires some objects to exist at least as long as it does so this
/// class contains instances of those objects.
///
/// FIXME: These objects should really come from somewhere more global instead
/// of being recreated for every Transform subclass, especially diagnostics.
class RewriterContainer {
public:
  RewriterContainer(clang::FileManager &Files,
                    const FileContentsByPath &InputStates)
    : DiagOpts(new clang::DiagnosticOptions()),
      DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()),
      Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
                    new clang::DiagnosticIDs()),
                  DiagOpts.getPtr(), &DiagnosticPrinter, false),
      Sources(Diagnostics, Files),
      Rewrite(Sources, DefaultLangOptions) {

    // Overwrite source manager's file contents with data from InputStates
    for (FileContentsByPath::const_iterator I = InputStates.begin(),
                                            E = InputStates.end();
         I != E; ++I) {
      Sources.overrideFileContents(Files.getFile(I->first),
                                   llvm::MemoryBuffer::getMemBuffer(I->second));
    }
  }

  clang::Rewriter &getRewriter() { return Rewrite; }

private:
  clang::LangOptions DefaultLangOptions;
  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
  clang::TextDiagnosticPrinter DiagnosticPrinter;
  clang::DiagnosticsEngine Diagnostics;
  clang::SourceManager Sources;
  clang::Rewriter Rewrite;
};

/// \brief Container for global options affecting all transforms.
struct TransformOptions {
  /// \brief Enable the use of performance timers.
  bool EnableTiming;

  /// \brief Maximum allowed level of risk.
  RiskLevel MaxRiskLevel;
};

/// \brief Abstract base class for all C++11 migration transforms.
///
/// Per-source performance timing is handled by the callbacks
/// handleBeginSource() and handleEndSource() if timing is enabled. See
/// clang::tooling::newFrontendActionFactory() for how to register a Transform
/// object for callbacks. When a Transform object is registered for
/// FrontendAction source file callbacks, this behaviour can be used to time
/// the application of a MatchFinder by subclasses. Durations are automatically
/// stored in a TimingVec.
class Transform : public clang::tooling::SourceFileCallbacks {
public:
  /// \brief Constructor
  /// \param Name Name of the transform for human-readable purposes (e.g. -help
  /// text)
  /// \param Options Collection of options that affect all transforms.
  Transform(llvm::StringRef Name, const TransformOptions &Options)
      : Name(Name), GlobalOptions(Options) {
    Reset();
  }

  virtual ~Transform() {}

  /// \brief Apply a transform to all files listed in \p SourcePaths.
  ///
  /// \p Database must contain information for how to compile all files in \p
  /// SourcePaths. \p InputStates contains the file contents of files in \p
  /// SourcePaths and should take precedence over content of files on disk.
  /// Upon return, \p ResultStates shall contain the result of performing this
  /// transform on the files listed in \p SourcePaths.
  virtual int apply(const FileContentsByPath &InputStates,
                    const clang::tooling::CompilationDatabase &Database,
                    const std::vector<std::string> &SourcePaths,
                    FileContentsByPath &ResultStates) = 0;

  /// \brief Query if changes were made during the last call to apply().
  bool getChangesMade() const { return AcceptedChanges > 0; }

  /// \brief Query if changes were not made due to conflicts with other changes
  /// made during the last call to apply() or if changes were too risky for the
  /// requested risk level.
  bool getChangesNotMade() const {
    return RejectedChanges > 0 || DeferredChanges > 0;
  }

  /// \brief Query the number of accepted changes.
  unsigned getAcceptedChanges() const { return AcceptedChanges; }
  /// \brief Query the number of changes considered too risky.
  unsigned getRejectedChanges() const { return RejectedChanges; }
  /// \brief Query the number of changes not made because they conflicted with
  /// early changes.
  unsigned getDeferredChanges() const { return DeferredChanges; }

  /// \brief Query transform name.
  llvm::StringRef getName() const { return Name; }

  /// \brief Reset internal state of the transform.
  ///
  /// Useful if calling apply() several times with one instantiation of a
  /// transform.
  void Reset() {
    AcceptedChanges = 0;
    RejectedChanges = 0;
    DeferredChanges = 0;
  }

  /// \brief Callback for notification of the start of processing of a source
  /// file by a FrontendAction. Starts a performance timer if timing was
  /// enabled.
  virtual bool handleBeginSource(clang::CompilerInstance &CI,
                                 llvm::StringRef Filename) LLVM_OVERRIDE;

  /// \brief Callback for notification of the end of processing of a source
  /// file by a FrontendAction. Stops a performance timer if timing was enabled
  /// and records the elapsed time. For a given source, handleBeginSource() and
  /// handleEndSource() are expected to be called in pairs.
  virtual void handleEndSource() LLVM_OVERRIDE;

  /// \brief Performance timing data is stored as a vector of pairs. Pairs are
  /// formed of:
  /// \li Name of source file.
  /// \li Elapsed time.
  typedef std::vector<std::pair<std::string, llvm::TimeRecord> > TimingVec;

  /// \brief Return an iterator to the start of collected timing data.
  TimingVec::const_iterator timing_begin() const { return Timings.begin(); }
  /// \brief Return an iterator to the start of collected timing data.
  TimingVec::const_iterator timing_end() const { return Timings.end(); }

protected:

  void setAcceptedChanges(unsigned Changes) {
    AcceptedChanges = Changes;
  }
  void setRejectedChanges(unsigned Changes) {
    RejectedChanges = Changes;
  }
  void setDeferredChanges(unsigned Changes) {
    DeferredChanges = Changes;
  }

  /// \brief Allows subclasses to manually add performance timer data.
  ///
  /// \p Label should probably include the source file name somehow as the
  /// duration info is simply added to the vector of timing data which holds
  /// data for all sources processed by this transform.
  void addTiming(llvm::StringRef Label, llvm::TimeRecord Duration);

  const TransformOptions &Options() { return GlobalOptions; }

private:
  const std::string Name;
  const TransformOptions &GlobalOptions;
  TimingVec Timings;
  unsigned AcceptedChanges;
  unsigned RejectedChanges;
  unsigned DeferredChanges;
};

#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
OpenPOWER on IntegriCloud