cpp11-migrate: Add Replace-AutoPtr Transform

Add a new transform to replace uses of 'std::auto_ptr' by 'std::unique_ptr'.
Copy-ctor and assign-operator are wrapped with a call to 'std::move()'.

Note that until header modification is ready it is not that useful, that's why
it's marked as (EXPERIMENTAL) in the command line description and a "Known
Limitations" section is present in the transform documentation.

Author: Guillaume Papin <guillaume.papin@epitech.eu>
llvm-svn: 185535
This commit is contained in:
Edwin Vane 2013-07-03 13:21:24 +00:00
parent 4eca75df00
commit 5ee6110817
18 changed files with 953 additions and 3 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

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

View File

@ -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

View File

@ -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}
)

View File

@ -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.

View File

@ -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 \

View File

@ -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`.

View File

@ -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.

View File

@ -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

View File

@ -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`

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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