| //===-- 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/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; |
| |
| extern template class llvm::Registry<TransformFactory>; |
| |
| #endif // CLANG_MODERNIZE_TRANSFORM_H |