diff options
Diffstat (limited to 'clang-tools-extra')
18 files changed, 953 insertions, 3 deletions
diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp new file mode 100644 index 00000000000..f3bc7a9f214 --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp @@ -0,0 +1,55 @@ +//===-- ReplaceAutoPtr.cpp ---------- std::auto_ptr replacement -*- 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 implementation of the ReplaceAutoPtrTransform +/// class. +/// +//===----------------------------------------------------------------------===// + +#include "ReplaceAutoPtr.h" +#include "ReplaceAutoPtrActions.h" +#include "ReplaceAutoPtrMatchers.h" + +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" + +using namespace clang; +using namespace clang::tooling; +using namespace clang::ast_matchers; + +int +ReplaceAutoPtrTransform::apply(FileOverrides &InputStates, + const CompilationDatabase &Database, + const std::vector<std::string> &SourcePaths) { + ClangTool Tool(Database, SourcePaths); + + unsigned AcceptedChanges = 0; + + MatchFinder Finder; + AutoPtrReplacer Replacer(getReplacements(), AcceptedChanges, + /*Owner=*/*this); + OwnershipTransferFixer Fixer(getReplacements(), AcceptedChanges, + /*Owner=*/*this); + + Finder.addMatcher(makeAutoPtrTypeLocMatcher(), &Replacer); + Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer); + Finder.addMatcher(makeTransferOwnershipExprMatcher(), &Fixer); + + setOverrides(InputStates); + + if (Tool.run(createActionFactory(Finder))) { + llvm::errs() << "Error encountered during translation.\n"; + return 1; + } + + setAcceptedChanges(AcceptedChanges); + + return 0; +} diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.h b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.h new file mode 100644 index 00000000000..f4e8f6fcc2c --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.h @@ -0,0 +1,54 @@ +//===-- ReplaceAutoPtr.h ------------ std::auto_ptr replacement -*- 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 of the ReplaceAutoPtrTransform +/// class. +/// +//===----------------------------------------------------------------------===// +#ifndef CPP11_MIGRATE_REPLACE_AUTO_PTR_H +#define CPP11_MIGRATE_REPLACE_AUTO_PTR_H + +#include "Core/Transform.h" +#include "llvm/Support/Compiler.h" + +/// \brief Subclass of Transform that transforms the deprecated \c std::auto_ptr +/// into the C++11 \c std::unique_ptr. +/// +/// Note that both the \c std::auto_ptr type and the transfer of ownership are +/// transformed. \c std::auto_ptr provides two ways to transfer the ownership, +/// the copy-constructor and the assignment operator. Unlike most classes theses +/// operations do not 'copy' the resource but they 'steal' it. +/// \c std::unique_ptr uses move semantics instead, which makes the intent of +/// transferring the resource explicit. This difference between the two smart +/// pointers requires to wrap the copy-ctor and assign-operator with +/// \c std::move(). +/// +/// For example, given: +/// \code +/// std::auto_ptr<int> i, j; +/// i = j; +/// \endcode +/// the code is transformed to: +/// \code +/// std::unique_ptr<int> i, j; +/// i = std::move(j); +/// \endcode +class ReplaceAutoPtrTransform : public Transform { +public: + ReplaceAutoPtrTransform(const TransformOptions &Options) + : Transform("ReplaceAutoPtr", Options) {} + + /// \see Transform::run(). + virtual int apply(FileOverrides &InputStates, + const clang::tooling::CompilationDatabase &Database, + const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; +}; + +#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_H diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp new file mode 100644 index 00000000000..d80c0795ce2 --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp @@ -0,0 +1,107 @@ +//===-- ReplaceAutoPtrActions.cpp --- std::auto_ptr replacement -*- 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 contains the definition of the ASTMatcher callback +/// for the ReplaceAutoPtr transform. +/// +//===----------------------------------------------------------------------===// + +#include "ReplaceAutoPtrActions.h" +#include "ReplaceAutoPtrMatchers.h" +#include "Core/Transform.h" + +#include "clang/AST/ASTContext.h" +#include "clang/Lex/Lexer.h" + +using namespace clang; +using namespace clang::tooling; +using namespace clang::ast_matchers; + +namespace { + +/// \brief Verifies that the token at \p BeginningOfToken is 'auto_ptr'. +bool checkTokenIsAutoPtr(clang::SourceLocation BeginningOfToken, + const clang::SourceManager &SM, + const clang::LangOptions &LangOptions) { + llvm::SmallVector<char, 8> Buffer; + bool Invalid = false; + llvm::StringRef Res = + Lexer::getSpelling(BeginningOfToken, Buffer, SM, LangOptions, &Invalid); + + if (Invalid) + return false; + + return Res == "auto_ptr"; +} + +} // end anonymous namespace + +void AutoPtrReplacer::run(const MatchFinder::MatchResult &Result) { + SourceManager &SM = *Result.SourceManager; + SourceLocation IdentifierLoc; + + if (const TypeLoc *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) { + IdentifierLoc = locateFromTypeLoc(*TL, SM); + } else { + const UsingDecl *D = Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId); + assert(D && "Bad Callback. No node provided."); + IdentifierLoc = locateFromUsingDecl(D, SM); + } + + if (IdentifierLoc.isMacroID()) + IdentifierLoc = SM.getSpellingLoc(IdentifierLoc); + + if (!Owner.isFileModifiable(SM, IdentifierLoc)) + return; + + // make sure that only the 'auto_ptr' token is replaced and not the template + // aliases [temp.alias] + if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions())) + return; + + Replace.insert( + Replacement(SM, IdentifierLoc, strlen("auto_ptr"), "unique_ptr")); + ++AcceptedChanges; +} + +SourceLocation AutoPtrReplacer::locateFromTypeLoc(TypeLoc AutoPtrTypeLoc, + const SourceManager &SM) { + TemplateSpecializationTypeLoc TL = + AutoPtrTypeLoc.getAs<TemplateSpecializationTypeLoc>(); + if (TL.isNull()) + return SourceLocation(); + + return TL.getTemplateNameLoc(); +} + +SourceLocation +AutoPtrReplacer::locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl, + const SourceManager &SM) { + return UsingAutoPtrDecl->getNameInfo().getBeginLoc(); +} + +void OwnershipTransferFixer::run(const MatchFinder::MatchResult &Result) { + SourceManager &SM = *Result.SourceManager; + const Expr *E = Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId); + assert(E && "Bad Callback. No node provided."); + + CharSourceRange Range = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions()); + + if (Range.isInvalid()) + return; + + if (!Owner.isFileModifiable(SM, Range.getBegin())) + return; + + Replace.insert(Replacement(SM, Range.getBegin(), 0, "std::move(")); + Replace.insert(Replacement(SM, Range.getEnd(), 0, ")")); + AcceptedChanges += 2; +} diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.h b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.h new file mode 100644 index 00000000000..7369e9e5c46 --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.h @@ -0,0 +1,102 @@ +//===-- ReplaceAutoPtrActions.h ----- std::auto_ptr replacement -*- 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 contains the declaration of the ASTMatcher callback +/// for the ReplaceAutoPtr transform. +/// +//===----------------------------------------------------------------------===// +#ifndef CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H +#define CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H + +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Refactoring.h" + +class Transform; + +/// \brief The callback to be used when replacing the \c std::auto_ptr types and +/// using declarations. +class AutoPtrReplacer : public clang::ast_matchers::MatchFinder::MatchCallback { +public: + AutoPtrReplacer(clang::tooling::Replacements &Replace, + unsigned &AcceptedChanges, const Transform &Owner) + : Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {} + + /// \brief Entry point to the callback called when matches are made. + virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) + LLVM_OVERRIDE; + +private: + /// \brief Locates the \c auto_ptr token when it is referred by a \c TypeLoc. + /// + /// \code + /// std::auto_ptr<int> i; + /// ^~~~~~~~~~~~~ + /// \endcode + /// The caret represents the location returned and the tildes cover the + /// parameter \p AutoPtrTypeLoc. + /// + /// \return An invalid \c SourceLocation if not found, otherwise the location + /// of the beginning of the \c auto_ptr token. + clang::SourceLocation locateFromTypeLoc(clang::TypeLoc AutoPtrTypeLoc, + const clang::SourceManager &SM); + + /// \brief Locates the \c auto_ptr token in using declarations. + /// + /// \code + /// using std::auto_ptr; + /// ^ + /// \endcode + /// The caret represents the location returned. + /// + /// \return An invalid \c SourceLocation if not found, otherwise the + /// location of the beginning of the \c auto_ptr token. + clang::SourceLocation + locateFromUsingDecl(const clang::UsingDecl *UsingAutoPtrDecl, + const clang::SourceManager &SM); + +private: + clang::tooling::Replacements &Replace; + unsigned &AcceptedChanges; + const Transform &Owner; +}; + +/// \brief The callback to be used to fix the ownership transfers of +/// \c auto_ptr, +/// +/// \c unique_ptr requires to use \c std::move() explicitly in order to transfer +/// the ownership. +/// +/// Given: +/// \code +/// std::auto_ptr<int> a, b; +/// a = b; +/// \endcode +/// The last statement is transformed to: +/// \code +/// a = std::move(b); +/// \endcode +class OwnershipTransferFixer + : public clang::ast_matchers::MatchFinder::MatchCallback { +public: + OwnershipTransferFixer(clang::tooling::Replacements &Replace, + unsigned &AcceptedChanges, const Transform &Owner) + : Replace(Replace), AcceptedChanges(AcceptedChanges), Owner(Owner) {} + + /// \brief Entry point to the callback called when matches are made. + virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) + LLVM_OVERRIDE; + +private: + clang::tooling::Replacements &Replace; + unsigned &AcceptedChanges; + const Transform &Owner; +}; + +#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp new file mode 100644 index 00000000000..64bff2c2211 --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp @@ -0,0 +1,113 @@ +//===-- ReplaceAutoPtrMatchers.cpp - std::auto_ptr replacement -*- 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 contains the definitions for matcher-generating functions +/// and names for bound nodes found by AST matchers. +/// +//===----------------------------------------------------------------------===// + +#include "ReplaceAutoPtrMatchers.h" + +const char *AutoPtrTokenId = "AutoPtrTokenId"; +const char *AutoPtrOwnershipTransferId = "AutoPtrOwnershipTransferId"; + +namespace clang { +namespace ast_matchers { + +/// \brief Matches expressions that are lvalues. +/// +/// In the following example, a[0] matches expr(isLValue()): +/// \code +/// std::string a[2]; +/// std::string b; +/// b = a[0]; +/// b = "this string won't match"; +/// \endcode +AST_MATCHER(Expr, isLValue) { + return Node.getValueKind() == VK_LValue; +} + +/// \brief Matches declarations whose declaration context is the C++ standard +/// library namespace \c std. +/// +/// Note that inline namespaces are silently ignored during the lookup since +/// both libstdc++ and libc++ are known to use them for versioning purposes. +/// +/// Given +/// \code +/// namespace ns { +/// struct my_type {}; +/// using namespace std; +/// } +/// +/// using std::vector; +/// using ns::my_type; +/// using ns::list; +/// \endcode +/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(isFromStdNamespace()))) +/// matches "using std::vector" and "using ns::list". +AST_MATCHER(Decl, isFromStdNamespace) { + const DeclContext *D = Node.getDeclContext(); + + while (D->isInlineNamespace()) + D = D->getParent(); + + if (!D->isNamespace() || !D->getParent()->isTranslationUnit()) + return false; + + const IdentifierInfo *Info = cast<NamespaceDecl>(D)->getIdentifier(); + + return Info && Info->isStr("std"); +} + +} // end namespace ast_matchers +} // end namespace clang + +using namespace clang; +using namespace clang::ast_matchers; + +// shared matchers +static DeclarationMatcher AutoPtrDecl = + recordDecl(hasName("auto_ptr"), isFromStdNamespace()); + +static TypeMatcher AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); + +// Matcher that finds expressions that are candidates to be wrapped with +// 'std::move()'. +// +// Binds the id \c AutoPtrOwnershipTransferId to the expression. +static StatementMatcher MovableArgumentMatcher = expr( + allOf(isLValue(), hasType(AutoPtrType))).bind(AutoPtrOwnershipTransferId); + +TypeLocMatcher makeAutoPtrTypeLocMatcher() { + // skip elaboratedType() as the named type will match soon thereafter. + return typeLoc(loc(qualType(AutoPtrType, unless(elaboratedType())))) + .bind(AutoPtrTokenId); +} + +DeclarationMatcher makeAutoPtrUsingDeclMatcher() { + return usingDecl(hasAnyUsingShadowDecl(hasTargetDecl( + allOf(hasName("auto_ptr"), isFromStdNamespace())))).bind(AutoPtrTokenId); +} + +StatementMatcher makeTransferOwnershipExprMatcher() { + StatementMatcher assignOperator = + operatorCallExpr(allOf( + hasOverloadedOperatorName("="), + callee(methodDecl(ofClass(AutoPtrDecl))), + hasArgument(1, MovableArgumentMatcher))); + + StatementMatcher copyCtor = + constructExpr(allOf(hasType(AutoPtrType), + argumentCountIs(1), + hasArgument(0, MovableArgumentMatcher))); + + return anyOf(assignOperator, copyCtor); +} diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h new file mode 100644 index 00000000000..5d1e7bcec6e --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h @@ -0,0 +1,63 @@ +//===-- ReplaceAutoPtrMatchers.h --- std::auto_ptr replacement -*- 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 contains the declarations for matcher-generating functions +/// and names for bound nodes found by AST matchers. +/// +//===----------------------------------------------------------------------===// +#ifndef CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H +#define CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H + +#include "clang/ASTMatchers/ASTMatchers.h" + +/// Names to bind with matched expressions. +extern const char *AutoPtrTokenId; +extern const char *AutoPtrOwnershipTransferId; + +/// \brief Creates a matcher that finds the locations of types referring to the +/// \c std::auto_ptr() type. +/// +/// \code +/// std::auto_ptr<int> a; +/// ^~~~~~~~~~~~~ +/// +/// typedef std::auto_ptr<int> int_ptr_t; +/// ^~~~~~~~~~~~~ +/// +/// std::auto_ptr<int> fn(std::auto_ptr<int>); +/// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ +/// +/// <etc...> +/// \endcode +clang::ast_matchers::TypeLocMatcher makeAutoPtrTypeLocMatcher(); + +/// \brief Creates a matcher that finds the using declarations referring to +/// \c std::auto_ptr. +/// +/// \code +/// using std::auto_ptr; +/// ^~~~~~~~~~~~~~~~~~~ +/// \endcode +clang::ast_matchers::DeclarationMatcher makeAutoPtrUsingDeclMatcher(); + +/// \brief Creates a matcher that finds the \c std::auto_ptr copy-ctor and +/// assign-operator expressions. +/// +/// \c AutoPtrOwnershipTransferId is assigned to the argument of the expression, +/// this is the part that has to be wrapped by \c std::move(). +/// +/// \code +/// std::auto_ptr<int> i, j; +/// i = j; +/// ~~~~^ +/// \endcode +clang::ast_matchers::StatementMatcher makeTransferOwnershipExprMatcher(); + +#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt b/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt index 72aa68b8905..e03fbee3424 100644 --- a/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt +++ b/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt @@ -19,6 +19,9 @@ list(APPEND Cpp11MigrateSources ${UseAutoSources}) file(GLOB_RECURSE AddOverrideSources "../AddOverride/*.cpp") list(APPEND Cpp11MigrateSources ${AddOverrideSources}) +file(GLOB_RECURSE ReplaceAutoPtrSources "../ReplaceAutoPtr/*.cpp") +list(APPEND Cpp11MigrateSources ${ReplaceAutoPtrSources}) + add_clang_executable(cpp11-migrate ${Cpp11MigrateSources} ) diff --git a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp index f5b3818f7f0..1722de9fe68 100644 --- a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp +++ b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp @@ -23,6 +23,7 @@ #include "UseNullptr/UseNullptr.h" #include "UseAuto/UseAuto.h" #include "AddOverride/AddOverride.h" +#include "ReplaceAutoPtr/ReplaceAutoPtr.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" @@ -105,6 +106,10 @@ int main(int argc, const char **argv) { TransformManager.registerTransform( "add-override", "Make use of override specifier where possible", &ConstructTransform<AddOverrideTransform>); + TransformManager.registerTransform( + "replace-auto_ptr", "Replace auto_ptr (deprecated) by unique_ptr" + " (EXPERIMENTAL)", + &ConstructTransform<ReplaceAutoPtrTransform>); // Add more transform options here. // This causes options to be parsed. diff --git a/clang-tools-extra/cpp11-migrate/tool/Makefile b/clang-tools-extra/cpp11-migrate/tool/Makefile index c5f5435c1e9..5185163d008 100644 --- a/clang-tools-extra/cpp11-migrate/tool/Makefile +++ b/clang-tools-extra/cpp11-migrate/tool/Makefile @@ -30,6 +30,8 @@ SOURCES += $(addprefix ../UseAuto/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../UseAut BUILT_SOURCES += $(ObjDir)/../UseAuto/.objdir SOURCES += $(addprefix ../AddOverride/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../AddOverride/*.cpp))) BUILT_SOURCES += $(ObjDir)/../AddOverride/.objdir +SOURCES += $(addprefix ../ReplaceAutoPtr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../ReplaceAutoPtr/*.cpp))) +BUILT_SOURCES += $(ObjDir)/../ReplaceAutoPtr/.objdir LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc mcparser option USEDLIBS = migrateCore.a clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ diff --git a/clang-tools-extra/docs/MigratorUsage.rst b/clang-tools-extra/docs/MigratorUsage.rst index 04edd5a007e..7b0a8a530c6 100644 --- a/clang-tools-extra/docs/MigratorUsage.rst +++ b/clang-tools-extra/docs/MigratorUsage.rst @@ -126,3 +126,9 @@ Transform-Specific Command Line Options projects that use such macros to maintain build compatibility with non-C++11 code. +.. option:: -replace-auto_ptr + + Replace ``std::auto_ptr`` (deprecated in C++11) by ``std::unique_ptr`` and + wrap calls to the copy constructor and assignment operator with + ``std::move()``. + See :doc:`ReplaceAutoPtrTransform`. diff --git a/clang-tools-extra/docs/README.txt b/clang-tools-extra/docs/README.txt index 037fedab5ad..4b607775830 100644 --- a/clang-tools-extra/docs/README.txt +++ b/clang-tools-extra/docs/README.txt @@ -1,6 +1,6 @@ ------------------------------------------------------------- -Documetation for the tools of clang-tools-extra repo project ------------------------------------------------------------- +------------------------------------------------------------- +Documentation for the tools of clang-tools-extra repo project +------------------------------------------------------------- Sphinx and doxygen documentation is generated by executing make. diff --git a/clang-tools-extra/docs/ReplaceAutoPtrTransform.rst b/clang-tools-extra/docs/ReplaceAutoPtrTransform.rst new file mode 100644 index 00000000000..ec4cfdb997c --- /dev/null +++ b/clang-tools-extra/docs/ReplaceAutoPtrTransform.rst @@ -0,0 +1,72 @@ +.. index:: Replace-AutoPtr Transform + +========================= +Replace-AutoPtr Transform +========================= + +The Replace-AutoPtr Transform replaces the uses of the deprecated class +``std::auto_ptr`` by ``std::unique_ptr`` (introduced in C++11). The transfer of +ownership, done by the copy-constructor and the assignment operator, is changed +to match ``std::unique_ptr`` usage by using explicit calls to ``std::move()``. +The transform is enabled with the :option:`-replace-auto_ptr` option of +:program:`cpp11-migrate`. + +Migration example: + +.. code-block:: c++ + + -void take_ownership_fn(std::auto_ptr<int> int_ptr); + +void take_ownership_fn(std::unique_ptr<int> int_ptr); + + void f(int x) { + - std::auto_ptr<int> a(new int(x)); + - std::auto_ptr<int> b; + + std::unique_ptr<int> a(new int(x)); + + std::unique_ptr<int> b; + + - b = a; + - take_ownership_fn(b); + + b = std::move(a); + + take_ownership_fn(std::move(b)); + } + + +Known Limitations +================= +* If headers modification is not activated or if a header is not allowed to be + changed this transform will produce broken code (compilation error), where the + the headers' code will stay unchanged while the code using them will be + changed. + +* Client code that declares a reference to an ``std::auto_ptr`` coming from code + that can't be migrated (such as a header coming from a 3\ :sup:`rd` party + library) will produce a compilation error after migration. This is because the + type of the reference will be changed to ``std::unique_ptr`` but the type + returned by the library won't change, binding a reference to + ``std::unique_ptr`` from an ``std::auto_ptr``. This pattern doesn't make much + sense and usually ``std::auto_ptr`` are stored by value (otherwise what is the + point in using them instead of a reference or a pointer?). + + .. code-block:: c++ + + // <3rd-party header...> + std::auto_ptr<int> get_value(); + const std::auto_ptr<int> & get_ref(); + + // <calling code (with migration)...> + -std::auto_ptr<int> a(get_value()); + +std::unique_ptr<int> a(get_value()); // ok, unique_ptr constructed from auto_ptr + + -const std::auto_ptr<int> & p = get_ptr(); + +const std::unique_ptr<int> & p = get_ptr(); // won't compile + +* Non-instantiated templates aren't modified. + + .. code-block:: c++ + + template <typename X> + void f() { + std::auto_ptr<X> p; + } + + // only 'f<int>()' (or similar) will trigger the replacement diff --git a/clang-tools-extra/docs/cpp11-migrate.rst b/clang-tools-extra/docs/cpp11-migrate.rst index 9afe72f5194..faed1431de3 100644 --- a/clang-tools-extra/docs/cpp11-migrate.rst +++ b/clang-tools-extra/docs/cpp11-migrate.rst @@ -11,6 +11,7 @@ C++11 Migrator User's Manual UseNullptrTransform LoopConvertTransform AddOverrideTransform + ReplaceAutoPtrTransform MigratorUsage :program:`cpp11-migrate` is a standalone tool used to automatically convert @@ -113,3 +114,5 @@ independently enabled. The transforms currently implemented are: * :doc:`UseAutoTransform` * :doc:`AddOverrideTransform` + +* :doc:`ReplaceAutoPtrTransform` diff --git a/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/Inputs/basic.h b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/Inputs/basic.h new file mode 100644 index 00000000000..48b0ee4f67c --- /dev/null +++ b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/Inputs/basic.h @@ -0,0 +1,56 @@ +#ifndef INPUTS_BASIC_H +#define INPUTS_BASIC_H + +#include "memory_stub.h" + +// Instrumentation for auto_ptr_ref test +// @{ +struct Base {}; +struct Derived : Base {}; +std::auto_ptr<Derived> create_derived_ptr(); +// CHECK: std::unique_ptr<Derived> create_derived_ptr(); +// } + +// Test function return values (declaration) +std::auto_ptr<char> f_5(); +// CHECK: std::unique_ptr<char> f_5() + +// Test function parameters +void f_6(std::auto_ptr<int>); +// CHECK: void f_6(std::unique_ptr<int>); +void f_7(const std::auto_ptr<int> &); +// CHECK: void f_7(const std::unique_ptr<int> &); + +// Test on record type fields +struct A { + std::auto_ptr<int> field; + // CHECK: std::unique_ptr<int> field; + + typedef std::auto_ptr<int> int_ptr_type; + // CHECK: typedef std::unique_ptr<int> int_ptr_type; +}; + +// Test template WITH instantiation +template <typename T> struct B { + typedef typename std::auto_ptr<T> created_type; + // CHECK: typedef typename std::unique_ptr<T> created_type; + + created_type create() { return std::auto_ptr<T>(new T()); } + // CHECK: created_type create() { return std::unique_ptr<T>(new T()); } +}; + +// Test 'using' in a namespace (declaration) +namespace ns_1 { +// Test multiple using declarations +using std::auto_ptr; +using std::auto_ptr; +// CHECK: using std::unique_ptr; +// CHECK-NEXT: using std::unique_ptr; +} + +namespace ns_2 { +template <typename T> struct auto_ptr {}; +// CHECK: template <typename T> struct auto_ptr {}; +} + +#endif // INPUTS_BASIC_H diff --git a/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/Inputs/memory_stub.h b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/Inputs/memory_stub.h new file mode 100644 index 00000000000..89e4e0ec533 --- /dev/null +++ b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/Inputs/memory_stub.h @@ -0,0 +1,61 @@ +//===-----------------------------------------------------------*- C++ -*--===// +// +// This file contains a shell implementation of the 'auto_ptr' type from the +// standard library. This shell aims to support the variations between standard +// library implementations. +// +// Variations for how 'auto_ptr' is presented: +// 1. Defined directly in namespace std +// 2. Use a versioned inline namespace in std (default on libc++). +// +// Use the preprocessor to define USE_INLINE_NAMESPACE=1 and use the second +// variation. +// +//===----------------------------------------------------------------------===// + +namespace std { + +#if USE_INLINE_NAMESPACE +inline namespace _1 { +#endif + +template <class Y> struct auto_ptr_ref { + Y *y_; +}; + +template <class X> class auto_ptr { +public: + typedef X element_type; + // D.10.1.1 construct/copy/destroy: + explicit auto_ptr(X *p = 0) throw() {} + auto_ptr(auto_ptr &) throw() {} + template <class Y> auto_ptr(auto_ptr<Y> &) throw() {} + auto_ptr &operator=(auto_ptr &) throw() { return *this; } + template <class Y> auto_ptr &operator=(auto_ptr<Y> &) throw() { + return *this; + } + auto_ptr &operator=(auto_ptr_ref<X> r) throw() { return *this; } + ~auto_ptr() throw() {} + // D.10.1.3 conversions: + auto_ptr(auto_ptr_ref<X> r) throw() : x_(r.y_) {} + template <class Y> operator auto_ptr_ref<Y>() throw() { + auto_ptr_ref<Y> r; + r.y_ = x_; + return r; + } + template <class Y> operator auto_ptr<Y>() throw() { return auto_ptr<Y>(x_); } + +private: + X *x_; +}; + +template <> class auto_ptr<void> { +public: + typedef void element_type; +}; + +#if USE_INLINE_NAMESPACE +} // namespace _1 +#endif + +} // end namespace std diff --git a/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/basic.cpp b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/basic.cpp new file mode 100644 index 00000000000..690ede26533 --- /dev/null +++ b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/basic.cpp @@ -0,0 +1,154 @@ +// RUN: mkdir -p %T/Inputs +// +// Without inline namespace: +// +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic.h > %T/Inputs/basic.h +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/memory_stub.h > %T/Inputs/memory_stub.h +// RUN: cpp11-migrate -headers -include=%T -replace-auto_ptr %t.cpp -- \ +// RUN: -std=c++11 -I %T +// RUN: FileCheck -input-file=%t.cpp %s +// RUN: FileCheck -input-file=%T/Inputs/basic.h %S/Inputs/basic.h +// +// With inline namespace: +// +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic.h > %T/Inputs/basic.h +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/memory_stub.h > %T/Inputs/memory_stub.h +// RUN: cpp11-migrate -headers -include=%T -replace-auto_ptr %t.cpp -- \ +// RUN: -DUSE_INLINE_NAMESPACE=1 -std=c++11 -I %T +// RUN: FileCheck -input-file=%t.cpp %s +// RUN: FileCheck -input-file=%T/Inputs/basic.h %S/Inputs/basic.h + +#include "Inputs/basic.h" + +void f_1() { + std::auto_ptr<int> a; + // CHECK: std::unique_ptr<int> a; + + // check that spaces aren't modified unnecessarily + std:: auto_ptr <int> b; + // CHECK: std:: unique_ptr <int> b; + std :: auto_ptr < char > c(new char()); + // CHECK: std :: unique_ptr < char > c(new char()); + + // Test construction from a temporary + std::auto_ptr<char> d = std::auto_ptr<char>(); + // CHECK: std::unique_ptr<char> d = std::unique_ptr<char>(); + + typedef std::auto_ptr<int> int_ptr_t; + // CHECK: typedef std::unique_ptr<int> int_ptr_t; + int_ptr_t e(new int()); + // CHECK: int_ptr_t e(new int()); + + // Test pointers + std::auto_ptr<int> *f; + // CHECK: std::unique_ptr<int> *f; + + // Test 'static' declarations + static std::auto_ptr<int> g; + // CHECK: static std::unique_ptr<int> g; + + // Test with cv-qualifiers + const std::auto_ptr<int> h; + // CHECK: const std::unique_ptr<int> h; + volatile std::auto_ptr<int> i; + // CHECK: volatile std::unique_ptr<int> i; + const volatile std::auto_ptr<int> j; + // CHECK: const volatile std::unique_ptr<int> j; + + // Test auto and initializer-list + auto k = std::auto_ptr<int>{}; + // CHECK: auto k = std::unique_ptr<int>{}; + std::auto_ptr<int> l{std::auto_ptr<int>()}; + // CHECK: std::unique_ptr<int> l{std::unique_ptr<int>()}; + + // Test interlocked auto_ptr + std::auto_ptr<std::auto_ptr<int> > m; + // CHECK: std::unique_ptr<std::unique_ptr<int> > m; + + // Test temporaries + std::auto_ptr<char>(); + // CHECK: std::unique_ptr<char>(); + + // Test void-specialization + std::auto_ptr<void> n; + // CHECK: std::unique_ptr<void> n; + + // Test template WITH instantiation (instantiation) + B<double> o; + std::auto_ptr<double> p(o.create()); + // CHECK: std::unique_ptr<double> p(o.create()); + + // Test 'using' in a namespace ("definition") + ns_1::auto_ptr<int> q; + // CHECK: ns_1::unique_ptr<int> q; + + // Test construction with an 'auto_ptr_ref' + std::auto_ptr<Base> r(create_derived_ptr()); + // CHECK: std::unique_ptr<Base> r(create_derived_ptr()); +} + +// Test without the nested name specifiers +void f_2() { + using namespace std; + + auto_ptr<int> a; + // CHECK: unique_ptr<int> a; +} + +// Test using declaration +void f_3() { + using std::auto_ptr; + // CHECK: using std::unique_ptr; + + auto_ptr<int> a; + // CHECK: unique_ptr<int> a; +} + +// Test messing-up with macros +void f_4() { +#define MACRO_1 <char> + std::auto_ptr MACRO_1 p(new char()); +// CHECK: std::unique_ptr MACRO_1 p(new char()); +#define MACRO_2 auto_ptr + std::MACRO_2<int> q; +// CHECK: #define MACRO_2 unique_ptr +#define MACRO_3(Type) std::auto_ptr<Type> + MACRO_3(float)r(new float()); +// CHECK: #define MACRO_3(Type) std::unique_ptr<Type> +#define MACRO_4 std::auto_ptr + using MACRO_4; +// CHECK: #define MACRO_4 std::unique_ptr +#undef MACRO_1 +#undef MACRO_2 +#undef MACRO_3 +#undef MACRO_4 +} + +// Test function return values (definition) +std::auto_ptr<char> f_5() +// CHECK: std::unique_ptr<char> f_5() +{ + // Test constructor + return std::auto_ptr<char>(new char()); + // CHECK: return std::unique_ptr<char>(new char()); +} + +// Test that non-std auto_ptr aren't replaced +void f_8() { + ns_2::auto_ptr<char> a; + // CHECK: ns_2::auto_ptr<char> a; + using namespace ns_2; + auto_ptr<int> b; + // CHECK: auto_ptr<int> b; +} + +namespace std { +template <typename T> using aaaaaaaa = auto_ptr<T>; +} +// We want to avoid replacing 'aaaaaaaa' by unique_ptr here. It's better to +// change the type alias directly. +// XXX: maybe another test will be more relevant to test this potential error. +std::aaaaaaaa<int> d; +// CHECK: std::aaaaaaaa<int> d; diff --git a/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/move.cpp b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/move.cpp new file mode 100644 index 00000000000..d0e9ce14098 --- /dev/null +++ b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/move.cpp @@ -0,0 +1,63 @@ +// Without inline namespace: +// +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: cpp11-migrate -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 +// RUN: FileCheck -input-file=%t.cpp %s +// +// With inline namespace: +// +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: cpp11-migrate -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 \ +// RUN: -DUSE_INLINE_NAMESPACE=1 +// RUN: FileCheck -input-file=%t.cpp %s + +#include "memory_stub.h" + +void takes_ownership_fn(std::auto_ptr<int> x); +// CHECK: void takes_ownership_fn(std::unique_ptr<int> x); + +std::auto_ptr<int> get_by_value(); +// CHECK: std::unique_ptr<int> get_by_value(); + +class Wrapper { +public: + std::auto_ptr<int> &get_wrapped(); + +private: + std::auto_ptr<int> wrapped; +}; + +void f() { + std::auto_ptr<int> a, b, c; + // CHECK: std::unique_ptr<int> a, b, c; + Wrapper wrapper_a, wrapper_b; + + a = b; + // CHECK: a = std::move(b); + + wrapper_a.get_wrapped() = wrapper_b.get_wrapped(); + // CHECK: wrapper_a.get_wrapped() = std::move(wrapper_b.get_wrapped()); + + // Test that 'std::move()' is inserted when call to the + // copy-constructor are made. + takes_ownership_fn(c); + // CHECK: takes_ownership_fn(std::move(c)); + takes_ownership_fn(wrapper_a.get_wrapped()); + // CHECK: takes_ownership_fn(std::move(wrapper_a.get_wrapped())); + + std::auto_ptr<int> d[] = { std::auto_ptr<int>(new int(1)), + std::auto_ptr<int>(new int(2)) }; + std::auto_ptr<int> e = d[0]; + // CHECK: std::unique_ptr<int> d[] = { std::unique_ptr<int>(new int(1)), + // CHECK-NEXT: std::unique_ptr<int>(new int(2)) }; + // CHECK-NEXT: std::unique_ptr<int> e = std::move(d[0]); + + // Test that std::move() is not used when assigning an rvalue + std::auto_ptr<int> f; + f = std::auto_ptr<int>(new int(0)); + // CHECK: std::unique_ptr<int> f; + // CHECK-NEXT: f = std::unique_ptr<int>(new int(0)); + + std::auto_ptr<int> g = get_by_value(); + // CHECK: std::unique_ptr<int> g = get_by_value(); +} diff --git a/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/template_fail.cpp b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/template_fail.cpp new file mode 100644 index 00000000000..cdbf272c26b --- /dev/null +++ b/clang-tools-extra/test/cpp11-migrate/ReplaceAutoPtr/template_fail.cpp @@ -0,0 +1,31 @@ +// XFAIL: * +// +// Without inline namespace: +// +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: cpp11-migrate -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 +// RUN: FileCheck -input-file=%t.cpp %s +// +// With inline namespace: +// +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: cpp11-migrate -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 \ +// RUN: -DUSE_INLINE_NAMESPACE=1 +// RUN: FileCheck -input-file=%t.cpp %s + +#include "memory_stub.h" + +// Fail to modify when the template is never instantiated. +// +// This might not be an issue. If it's never used it doesn't really matter if +// it's changed or not. If it's a header and one of the source use it, then it +// will still be changed. +template <typename X> +void f() { + std::auto_ptr<X> p; + // CHECK: std::unique_ptr<X> p; +} + +// Alias template could be replaced if a matcher existed. +template <typename T> using aaaaaaaa = auto_ptr<T>; +// CHECK: template <typename T> using aaaaaaaa = unique_ptr<T>; |