diff options
Diffstat (limited to 'clang-tools-extra/cpp11-migrate/ReplaceAutoPtr')
6 files changed, 494 insertions, 0 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 |