diff options
Diffstat (limited to 'clang-tools-extra/cpp11-migrate')
10 files changed, 252 insertions, 14 deletions
diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp index d044002e10d..db38fa64b56 100644 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp +++ b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp @@ -61,6 +61,18 @@ bool AddOverrideTransform::handleBeginSource(clang::CompilerInstance &CI, } struct AddOverrideFactory : TransformFactory { + AddOverrideFactory() { + // if detecting macros is enabled, do not impose requirements on the + // compiler. It is assumed that the macros use is "C++11-aware", meaning it + // won't expand to override if the compiler doesn't support the specifier. + if (!DetectMacros) { + Since.Clang = Version(3, 0); + Since.Gcc = Version(4, 7); + Since.Icc = Version(14); + Since.Msvc = Version(8); + } + } + Transform *createTransform(const TransformOptions &Opts) LLVM_OVERRIDE { return new AddOverrideTransform(Opts); } diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp index ac3375316bb..92520638502 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; @@ -132,4 +133,36 @@ FrontendActionFactory *Transform::createActionFactory(MatchFinder &Finder) { return new ActionFactory(Finder, /*Owner=*/ *this); } +Version Version::getFromString(llvm::StringRef VersionStr) { + llvm::StringRef MajorStr, MinorStr; + Version V; + + llvm::tie(MajorStr, MinorStr) = VersionStr.split('.'); + if (!MinorStr.empty()) { + llvm::StringRef Ignore; + llvm::tie(MinorStr, Ignore) = MinorStr.split('.'); + if (MinorStr.getAsInteger(10, V.Minor)) + return Version(); + } + if (MajorStr.getAsInteger(10, V.Major)) + return Version(); + return V; +} + TransformFactory::~TransformFactory() {} + +namespace { +bool versionSupported(Version Required, Version AvailableSince) { + // null version, means no requirements, means supported + if (Required.isNull()) + return true; + return Required >= AvailableSince; +} +} // end anonymous namespace + +bool TransformFactory::supportsCompilers(CompilerVersions Required) const { + return versionSupported(Required.Clang, Since.Clang) && + versionSupported(Required.Gcc, Since.Gcc) && + versionSupported(Required.Icc, Since.Icc) && + versionSupported(Required.Msvc, Since.Msvc); +} diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.h b/clang-tools-extra/cpp11-migrate/Core/Transform.h index ca610b82b9d..bb8c116726d 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.h +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.h @@ -222,16 +222,74 @@ private: 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 it and implement the \c createTransform() -/// methods. Use \c TransformFactoryRegistry to register the transform globally. +/// 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) LLVM_OVERRIDE { /// return new MyTransform(Opts); /// } @@ -249,6 +307,17 @@ 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; diff --git a/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp b/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp index d58e4c6af70..93701796e24 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp @@ -37,17 +37,35 @@ void Transforms::registerTransforms() { I->getName(), cl::desc(I->getDesc()), cl::cat(TransformCategory)); } +bool Transforms::hasAnyExplicitOption() const { + for (OptionMap::const_iterator I = Options.begin(), E = Options.end(); I != E; + ++I) + if (*I->second) + return true; + return false; +} + void -Transforms::createSelectedTransforms(const TransformOptions &GlobalOptions) { +Transforms::createSelectedTransforms(const TransformOptions &GlobalOptions, + const CompilerVersions &RequiredVersions) { + // if at least one transform is set explicitly on the command line, do not + // enable non-explicit ones + bool EnableAllTransformsByDefault = !hasAnyExplicitOption(); + for (TransformFactoryRegistry::iterator I = TransformFactoryRegistry::begin(), E = TransformFactoryRegistry::end(); I != E; ++I) { - bool OptionEnabled = *Options[I->getName()]; + bool ExplicitlyEnabled = *Options[I->getName()]; + bool OptionEnabled = EnableAllTransformsByDefault || ExplicitlyEnabled; if (!OptionEnabled) continue; llvm::OwningPtr<TransformFactory> Factory(I->instantiate()); - ChosenTransforms.push_back(Factory->createTransform(GlobalOptions)); + if (Factory->supportsCompilers(RequiredVersions)) + ChosenTransforms.push_back(Factory->createTransform(GlobalOptions)); + else if (ExplicitlyEnabled) + llvm::errs() << "note: " << '-' << I->getName() + << ": transform not available for specified compilers\n"; } } diff --git a/clang-tools-extra/cpp11-migrate/Core/Transforms.h b/clang-tools-extra/cpp11-migrate/Core/Transforms.h index 527474d0568..18369407dda 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transforms.h +++ b/clang-tools-extra/cpp11-migrate/Core/Transforms.h @@ -30,6 +30,7 @@ class Option; } // namespace llvm class Transform; struct TransformOptions; +struct CompilerVersions; typedef Transform *(*TransformCreator)(const TransformOptions &); template <typename T> @@ -57,7 +58,8 @@ public: /// \brief Instantiate all transforms that were selected on the command line. /// /// Call *after* parsing options. - void createSelectedTransforms(const TransformOptions &Options); + void createSelectedTransforms(const TransformOptions &Options, + const CompilerVersions &RequiredVersions); /// \brief Return an iterator to the start of a container of instantiated /// transforms. @@ -68,6 +70,8 @@ public: const_iterator end() const { return ChosenTransforms.end(); } private: + bool hasAnyExplicitOption() const; + typedef llvm::StringMap<llvm::cl::opt<bool> *> OptionMap; private: diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp index 965ae4b25d0..73c2560e796 100644 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp +++ b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp @@ -68,6 +68,13 @@ int LoopConvertTransform::apply(FileOverrides &InputStates, } struct LoopConvertFactory : TransformFactory { + LoopConvertFactory() { + Since.Clang = Version(3, 0); + Since.Gcc = Version(4, 6); + Since.Icc = Version(13); + Since.Msvc = Version(11); + } + Transform *createTransform(const TransformOptions &Opts) LLVM_OVERRIDE { return new LoopConvertTransform(Opts); } diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp index 9d281ecdd67..47dce8e7c89 100644 --- a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp @@ -50,6 +50,13 @@ ReplaceAutoPtrTransform::apply(FileOverrides &InputStates, } struct ReplaceAutoPtrFactory : TransformFactory { + ReplaceAutoPtrFactory() { + Since.Clang = Version(3, 0); + Since.Gcc = Version(4, 6); + Since.Icc = Version(13); + Since.Msvc = Version(11); + } + Transform *createTransform(const TransformOptions &Opts) LLVM_OVERRIDE { return new ReplaceAutoPtrTransform(Opts); } diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp index 47c2cd53215..ccf49d88c92 100644 --- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp +++ b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp @@ -49,6 +49,13 @@ int UseAutoTransform::apply(FileOverrides &InputStates, } struct UseAutoFactory : TransformFactory { + UseAutoFactory() { + Since.Clang = Version(2, 9); + Since.Gcc = Version(4, 4); + Since.Icc = Version(12); + Since.Msvc = Version(10); + } + Transform *createTransform(const TransformOptions &Opts) LLVM_OVERRIDE { return new UseAutoTransform(Opts); } diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp index ba433ec77ae..afeec4a10af 100644 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp +++ b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp @@ -50,6 +50,13 @@ int UseNullptrTransform::apply(FileOverrides &InputStates, } struct UseNullptrFactory : TransformFactory { + UseNullptrFactory() { + Since.Clang = Version(3, 0); + Since.Gcc = Version(4, 6); + Since.Icc = Version(12, 1); + Since.Msvc = Version(10); + } + Transform *createTransform(const TransformOptions &Opts) LLVM_OVERRIDE { return new UseNullptrTransform(Opts); } diff --git a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp index 2ee4a069ff3..10370f959e2 100644 --- a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp +++ b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp @@ -24,6 +24,8 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Signals.h" @@ -36,8 +38,8 @@ TransformOptions GlobalOptions; static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); static cl::extrahelp MoreHelp( "EXAMPLES:\n\n" - "Use 'auto' type specifier, no compilation database:\n\n" - " cpp11-migrate -use-auto path/to/file.cpp -- -Ipath/to/include/\n" + "Apply all transforms on a given file, no compilation database:\n\n" + " cpp11-migrate path/to/file.cpp -- -Ipath/to/include/\n" "\n" "Convert for loops to the new ranged-based for loops on all files in a " "subtree\nand reformat the code automatically using the LLVM style:\n\n" @@ -47,7 +49,10 @@ static cl::extrahelp MoreHelp( "Make use of both nullptr and the override specifier, using git ls-files:\n" "\n" " git ls-files '*.cpp' | xargs -I{} cpp11-migrate -p build/path \\\n" - " -use-nullptr -add-override -override-macros {}\n"); + " -use-nullptr -add-override -override-macros {}\n" + "\n" + "Apply all transforms supported by both clang >= 3.0 and gcc >= 4.7:\n\n" + " cpp11-migrate -for-compilers=clang-3.0,gcc-4.7 foo.cpp -- -Ibar\n"); static cl::opt<RiskLevel, /*ExternalStorage=*/true> MaxRiskLevel( "risk", cl::desc("Select a maximum risk level:"), @@ -113,6 +118,68 @@ static cl::opt<bool, /*ExternalStorage=*/true> EnableHeaderModifications( cl::location(GlobalOptions.EnableHeaderModifications), cl::init(false)); +cl::opt<std::string> SupportedCompilers( + "for-compilers", cl::value_desc("string"), + cl::desc("Select transforms targeting the intersection of\n" + "language features supported by the given compilers.\n" + "Takes a comma-seperated list of <compiler>-<version>.\n" + "\t<compiler> can be any of: clang, gcc, icc, msvc\n" + "\t<version> is <major>[.<minor>]\n")); + +/// \brief Extract the minimum compiler versions as requested on the command +/// line by the switch \c -for-compilers. +/// +/// \param ProgName The name of the program, \c argv[0], used to print errors. +/// \param Error If an error occur while parsing the versions this parameter is +/// set to \c true, otherwise it will be left untouched. +static CompilerVersions handleSupportedCompilers(const char *ProgName, + bool &Error) { + if (SupportedCompilers.getNumOccurrences() == 0) + return CompilerVersions(); + CompilerVersions RequiredVersions; + llvm::SmallVector<llvm::StringRef, 4> Compilers; + + llvm::StringRef(SupportedCompilers).split(Compilers, ","); + + for (llvm::SmallVectorImpl<llvm::StringRef>::iterator I = Compilers.begin(), + E = Compilers.end(); + I != E; ++I) { + llvm::StringRef Compiler, VersionStr; + llvm::tie(Compiler, VersionStr) = I->split('-'); + Version *V = llvm::StringSwitch<Version *>(Compiler) + .Case("clang", &RequiredVersions.Clang) + .Case("gcc", &RequiredVersions.Gcc).Case("icc", &RequiredVersions.Icc) + .Case("msvc", &RequiredVersions.Msvc).Default(NULL); + + if (V == NULL) { + llvm::errs() << ProgName << ": " << Compiler + << ": unsupported platform\n"; + Error = true; + continue; + } + if (VersionStr.empty()) { + llvm::errs() << ProgName << ": " << *I + << ": missing version number in platform\n"; + Error = true; + continue; + } + + Version Version = Version::getFromString(VersionStr); + if (Version.isNull()) { + llvm::errs() + << ProgName << ": " << *I + << ": invalid version, please use \"<major>[.<minor>]\" instead of \"" + << VersionStr << "\"\n"; + Error = true; + continue; + } + // support the lowest version given + if (V->isNull() || Version < *V) + *V = Version; + } + return RequiredVersions; +} + /// \brief Creates the Reformatter if the format style option is provided, /// return a null pointer otherwise. /// @@ -161,10 +228,13 @@ int main(int argc, const char **argv) { GlobalOptions.EnableTiming = (TimingDirectoryName != NoTiming); // Check the reformatting style option - bool BadStyle = false; + bool CmdSwitchError = false; llvm::OwningPtr<Reformatter> ChangesReformatter( - handleFormatStyle(argv[0], BadStyle)); - if (BadStyle) + handleFormatStyle(argv[0], CmdSwitchError)); + + CompilerVersions RequiredVersions = + handleSupportedCompilers(argv[0], CmdSwitchError); + if (CmdSwitchError) return 1; // Populate the ModifiableHeaders structure if header modifications are @@ -176,10 +246,14 @@ int main(int argc, const char **argv) { .readListFromFile(IncludeFromFile, ExcludeFromFile); } - TransformManager.createSelectedTransforms(GlobalOptions); + TransformManager.createSelectedTransforms(GlobalOptions, RequiredVersions); if (TransformManager.begin() == TransformManager.end()) { - llvm::errs() << argv[0] << ": No selected transforms\n"; + if (SupportedCompilers.empty()) + llvm::errs() << argv[0] << ": no selected transforms\n"; + else + llvm::errs() << argv[0] + << ": no transforms available for specified compilers\n"; return 1; } |