forked from OSchip/llvm-project
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:
parent
4eca75df00
commit
5ee6110817
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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}
|
||||
)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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`
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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();
|
||||
}
|
|
@ -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>;
|
Loading…
Reference in New Issue