summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-modernize/Core/Transform.h
blob: 459d2a37eda4cbb92d24b80182c78c551525cc5d (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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
//===-- Core/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 declaration for the base Transform class from
/// which all transforms must subclass.
///
//===----------------------------------------------------------------------===//

#ifndef CLANG_MODERNIZE_TRANSFORM_H
#define CLANG_MODERNIZE_TRANSFORM_H

#include "Core/IncludeExcludeInfo.h"
#include "Core/Refactoring.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Registry.h"
#include "llvm/Support/Timer.h"
#include <string>
#include <vector>

/// \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 {
class CompilerInstance;
namespace tooling {
class CompilationDatabase;
class FrontendActionFactory;
} // namespace tooling
namespace ast_matchers {
class MatchFinder;
} // namespace ast_matchers
} // namespace clang

// \brief Maps main source file names to a TranslationUnitReplacements
// structure storing replacements for that translation unit.
typedef llvm::StringMap<clang::tooling::TranslationUnitReplacements>
TUReplacementsMap;

/// \brief To group transforms' options together when printing the help.
extern llvm::cl::OptionCategory TransformsOptionsCategory;

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

  /// \brief Contains information on which files are safe to transform and
  /// which aren't.
  IncludeExcludeInfo ModifiableFiles;

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

/// \brief Abstract base class for all C++11 migration transforms.
///
/// Subclasses must call createActionFactory() to create a
/// FrontendActionFactory to pass to ClangTool::run(). Subclasses are also
/// responsible for calling setOverrides() before calling ClangTool::run().
///
/// If timing is enabled (see TransformOptions), per-source performance timing
/// is recorded and stored in a TimingVec for later access with timing_begin()
/// and timing_end().
class Transform {
public:
  /// \brief Constructor
  /// \param Name Name of the transform for human-readable purposes (e.g. -help
  /// text)
  /// \param Options Global options that affect all Transforms.
  Transform(llvm::StringRef Name, const TransformOptions &Options);

  virtual ~Transform();

  /// \brief Apply a transform to all files listed in \p SourcePaths.
  ///
  /// \param[in] Database Contains information for how to compile all files in
  /// \p SourcePaths.
  /// \param[in] SourcePaths list of sources to transform.
  ///
  /// \returns \li 0 if successful
  ///          \li 1 otherwise
  virtual int apply(const clang::tooling::CompilationDatabase &Database,
                    const std::vector<std::string> &SourcePaths) = 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 Tests if the file containing \a Loc is allowed to be modified by
  /// the Modernizer.
  bool isFileModifiable(const clang::SourceManager &SM,
                        const clang::SourceLocation &Loc) const;

  /// \brief Whether a transformation with a risk level of \p RiskLevel is
  /// acceptable or not.
  bool isAcceptableRiskLevel(RiskLevel RiskLevel) const {
    return RiskLevel <= GlobalOptions.MaxRiskLevel;
  }

  /// \brief Called before parsing a translation unit for a FrontendAction.
  ///
  /// Transform uses this function to apply file overrides and start
  /// performance timers. Subclasses overriding this function must call it
  /// before returning.
  virtual bool handleBeginSource(clang::CompilerInstance &CI,
                                 llvm::StringRef Filename);

  /// \brief Called after FrontendAction has been run over a translation unit.
  ///
  /// Transform uses this function to stop performance timers. Subclasses
  /// overriding this function must call it before returning. A call to
  /// handleEndSource() for a given translation unit is expected to be called
  /// immediately after the corresponding handleBeginSource() call.
  virtual void handleEndSource();

  /// \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(); }

  /// \brief Add a Replacement to the list for the current translation unit.
  ///
  /// \returns \li true on success
  ///          \li false if there is no current translation unit
  bool addReplacementForCurrentTU(const clang::tooling::Replacement &R);

  /// \brief Accessor to Replacements across all transformed translation units.
  const TUReplacementsMap &getAllReplacements() const {
    return Replacements;
  }

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);

  /// \brief Provide access for subclasses to the TransformOptions they were
  /// created with.
  const TransformOptions &Options() { return GlobalOptions; }

  /// \brief Subclasses must call this function to create a
  /// FrontendActionFactory to pass to ClangTool.
  ///
  /// The factory returned by this function is responsible for calling back to
  /// Transform to call handleBeginSource() and handleEndSource().
  clang::tooling::FrontendActionFactory *
      createActionFactory(clang::ast_matchers::MatchFinder &Finder);

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

/// \brief Describes a version number of the form major[.minor] (minor being
/// optional).
struct Version {
  explicit Version(unsigned Major = 0, unsigned Minor = 0)
      : Major(Major), Minor(Minor) {}

  bool operator<(Version RHS) const {
    if (Major < RHS.Major)
      return true;
    if (Major == RHS.Major)
      return Minor < RHS.Minor;
    return false;
  }

  bool operator==(Version RHS) const {
    return Major == RHS.Major && Minor == RHS.Minor;
  }

  bool operator!=(Version RHS) const { return !(*this == RHS); }
  bool operator>(Version RHS) const { return RHS < *this; }
  bool operator<=(Version RHS) const { return !(*this > RHS); }
  bool operator>=(Version RHS) const { return !(*this < RHS); }

  bool isNull() const { return Minor == 0 && Major == 0; }
  unsigned getMajor() const { return Major; }
  unsigned getMinor() const { return Minor; }

  /// \brief Creates a version from a string of the form \c major[.minor].
  ///
  /// Note that any version component after \c minor is ignored.
  ///
  /// \return A null version is returned on error.
  static Version getFromString(llvm::StringRef VersionStr);

private:
  unsigned Major;
  unsigned Minor;
};

/// \brief Convenience structure to store the version of some compilers.
struct CompilerVersions {
  Version Clang, Gcc, Icc, Msvc;
};

/// \brief A factory that can instantiate a specific transform.
///
/// Each transform should subclass this class and implement
/// \c createTransform().
///
/// In the sub-classed factory constructor, specify the earliest versions since
/// the compilers in \c CompilerVersions support the feature introduced by the
/// transform. See the example below.
///
/// Note that you should use \c TransformFactoryRegistry to register the
/// transform globally.
///
/// Example:
/// \code
/// class MyTransform : public Transform { ... };
///
/// struct MyFactory : TransformFactory {
///   MyFactory() {
///     Since.Clang = Version(3, 0);
///     Since.Gcc = Version(4, 7);
///     Since.Icc = Version(12);
///     Since.Msvc = Version(10);
///   }
///
///   Transform *createTransform(const TransformOptions &Opts) override {
///     return new MyTransform(Opts);
///   }
/// };
///
/// // Register the factory using this statically initialized variable.
/// static TransformFactoryRegistry::Add<MyFactory>
/// X("my-transform", "<Short description of my transform>");
///
/// // This anchor is used to force the linker to link in the generated object
/// // file and thus register the factory.
/// volatile int MyTransformAnchorSource = 0;
/// \endcode
class TransformFactory {
public:
  virtual ~TransformFactory();
  virtual Transform *createTransform(const TransformOptions &) = 0;

  /// \brief Whether the transform is supported by the required compilers or
  /// not.
  bool supportsCompilers(CompilerVersions Required) const;

protected:
  /// \brief Since when the C++11 feature introduced by this transform has been
  /// available.
  ///
  /// Can be set by the sub-class in the constructor body.
  CompilerVersions Since;
};

typedef llvm::Registry<TransformFactory> TransformFactoryRegistry;

#endif // CLANG_MODERNIZE_TRANSFORM_H
OpenPOWER on IntegriCloud