Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -5,6 +5,7 @@ LoopConvertUtils.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp + ReplaceAutoPtrCheck.cpp UseAutoCheck.cpp UseNullptrCheck.cpp Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "LoopConvertCheck.h" #include "PassByValueCheck.h" +#include "ReplaceAutoPtrCheck.h" #include "UseAutoCheck.h" #include "UseNullptrCheck.h" @@ -26,6 +27,8 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck("modernize-loop-convert"); CheckFactories.registerCheck("modernize-pass-by-value"); + CheckFactories.registerCheck( + "modernize-replace-auto-ptr"); CheckFactories.registerCheck("modernize-use-auto"); CheckFactories.registerCheck("modernize-use-nullptr"); } @@ -35,6 +38,7 @@ auto &Opts = Options.CheckOptions; Opts["modernize-loop-convert.MinConfidence"] = "reasonable"; Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google". + Opts["modernize-replace-auto-ptr.IncludeStyle"] = "llvm"; // Also: "google". // Comma-separated list of macros that behave like NULL. Opts["modernize-use-nullptr.NullMacros"] = "NULL"; Index: clang-tidy/modernize/ReplaceAutoPtrCheck.h =================================================================== --- /dev/null +++ clang-tidy/modernize/ReplaceAutoPtrCheck.h @@ -0,0 +1,59 @@ +//===--- ReplaceAutoPtrCheck.h - clang-tidy----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H + +#include "../ClangTidy.h" +#include "../utils/IncludeInserter.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// \brief 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 these +/// 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 requeres to wrap the copy-ctor and assign-operator with +/// \c std::move(). +/// +/// For example, given: +/// \code +/// std::auto_ptr i, j; +/// i = j; +/// \endcode +/// This code is transformed to: +/// \code +/// std::unique_ptr i, j; +/// i = std::move(j); +/// \endcode +class ReplaceAutoPtrCheck : public ClangTidyCheck { +public: + ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void registerPPCallbacks(CompilerInstance &Compiler) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::unique_ptr Inserter; + const IncludeSorter::IncludeStyle IncludeStyle; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H Index: clang-tidy/modernize/ReplaceAutoPtrCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/ReplaceAutoPtrCheck.cpp @@ -0,0 +1,262 @@ +//===--- ReplaceAutoPtrCheck.cpp - clang-tidy------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ReplaceAutoPtrCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang; +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +const char AutoPtrTokenId[] = "AutoPrTokenId"; +const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId"; + +/// \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; } + +/// Matches declarations whose declaration context is the C++ standard library +/// namespace 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; +/// \code +/// +/// 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(D)->getIdentifier(); + + return (Info && Info->isStr("std")); +} + +/// \brief Matcher that finds auto_ptr declarations. +static DeclarationMatcher AutoPtrDecl = + recordDecl(hasName("auto_ptr"), isFromStdNamespace()); + +/// \brief Matches types declared as auto_ptr. +static TypeMatcher AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); + +/// \brief 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); + +/// \brief Creates a matcher that finds the locations of types referring to the +/// \c std::auto_ptr() type. +/// +/// \code +/// std::auto_ptr a; +/// ^~~~~~~~~~~~~ +/// +/// typedef std::auto_ptr int_ptr_t; +/// ^~~~~~~~~~~~~ +/// +/// std::auto_ptr fn(std::auto_ptr); +/// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ +/// +/// +/// \endcode +TypeLocMatcher makeAutoPtrTypeLocMatcher() { + // Skip elaboratedType() as the named type will match soon thereafter. + return typeLoc(loc(qualType(AutoPtrType, unless(elaboratedType())))) + .bind(AutoPtrTokenId); +} + +/// \brief Creates a matcher that finds the using declarations referring to +/// \c std::auto_ptr. +/// +/// \code +/// using std::auto_ptr; +/// ^~~~~~~~~~~~~~~~~~~ +/// \endcode +DeclarationMatcher makeAutoPtrUsingDeclMatcher() { + return usingDecl(hasAnyUsingShadowDecl(hasTargetDecl( + allOf(hasName("auto_ptr"), isFromStdNamespace())))) + .bind(AutoPtrTokenId); +} + +/// \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 i, j; +/// i = j; +/// ~~~~^ +/// \endcode +StatementMatcher makeTransferOwnershipExprMatcher() { + return anyOf(operatorCallExpr(allOf(hasOverloadedOperatorName("="), + callee(methodDecl(ofClass(AutoPtrDecl))), + hasArgument(1, MovableArgumentMatcher))), + constructExpr(allOf(hasType(AutoPtrType), argumentCountIs(1), + hasArgument(0, MovableArgumentMatcher)))); +} + +/// \brief Locates the \c auto_ptr token when it is referred by a \c TypeLoc. +/// +/// \code +/// std::auto_ptr 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. +static SourceLocation locateFromTypeLoc(const TypeLoc *AutoPtrTypeLoc, + const SourceManager &SM) { + auto TL = AutoPtrTypeLoc->getAs(); + if (TL.isNull()) + return SourceLocation(); + + return TL.getTemplateNameLoc(); +} + +/// \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. +static SourceLocation locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl, + const SourceManager &SM) { + return UsingAutoPtrDecl->getNameInfo().getBeginLoc(); +} + +/// \brief Verifies that the token at \p TokenStart is 'auto_ptr'. +static bool checkTokenIsAutoPtr(SourceLocation TokenStart, + const SourceManager &SM, + const LangOptions &LO) { + SmallVector Buffer; + bool Invalid = false; + StringRef Res = Lexer::getSpelling(TokenStart, Buffer, SM, LO, &Invalid); + + return (!Invalid && Res == "auto_ptr"); +} + +ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IncludeStyle(Options.get("IncludeStyle", "llvm") == "llvm" + ? IncludeSorter::IS_LLVM + : IncludeSorter::IS_Google) {} + +void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IncludeStyle", + IncludeStyle == IncludeSorter::IS_LLVM ? "llvm" : "google"); +} + +void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(makeAutoPtrTypeLocMatcher(), this); + Finder->addMatcher(makeAutoPtrUsingDeclMatcher(), this); + Finder->addMatcher(makeTransferOwnershipExprMatcher(), this); +} + +void ReplaceAutoPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) { + Inserter.reset(new IncludeInserter(Compiler.getSourceManager(), + Compiler.getLangOpts(), IncludeStyle)); + Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); +} + +void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) { + SourceManager &SM = *Result.SourceManager; + if (const auto *E = + Result.Nodes.getNodeAs(AutoPtrOwnershipTransferId)) { + CharSourceRange Range = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions()); + + if (Range.isInvalid()) + return; + + auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership") + << FixItHint::CreateInsertion(Range.getBegin(), "std::move(") + << FixItHint::CreateInsertion(Range.getEnd(), ")"); + + auto Insertion = + Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility", + /*IsAngled=*/true); + if (Insertion.hasValue()) + Diag << Insertion.getValue(); + + return; + } + + SourceLocation IdentifierLoc; + if (const auto *TL = Result.Nodes.getNodeAs(AutoPtrTokenId)) { + IdentifierLoc = locateFromTypeLoc(TL, SM); + } else if (const auto *D = + Result.Nodes.getNodeAs(AutoPtrTokenId)) { + IdentifierLoc = locateFromUsingDecl(D, SM); + } else { + llvm_unreachable("Bad Callback. No node provided."); + } + + if (IdentifierLoc.isMacroID()) + IdentifierLoc = SM.getSpellingLoc(IdentifierLoc); + + // Ensure that only the 'auto_ptr' token is replaced and not the template + // aliases. + if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions())) + return; + + SourceLocation EndLoc = + IdentifierLoc.getLocWithOffset(strlen("auto_ptr") - 1); + diag(IdentifierLoc, "auto_ptr is deprecated, use unique_ptr instead") + << FixItHint::CreateReplacement(SourceRange(IdentifierLoc, EndLoc), + "unique_ptr"); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: test/clang-tidy/Inputs/modernize-replace-auto-ptr/memory.h =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/modernize-replace-auto-ptr/memory.h @@ -0,0 +1,45 @@ +#ifndef INPUTS_MEMORY_H +#define INPUTS_MEMORY_H + +namespace std { + +inline namespace _1 { + +template struct auto_ptr_ref { + Y *y_; +}; + +template class auto_ptr { +public: + typedef X element_type; + explicit auto_ptr(X *p = 0) throw() {} + auto_ptr(auto_ptr &) throw() {} + template auto_ptr(auto_ptr &) throw() {} + auto_ptr &operator=(auto_ptr &) throw() { return *this; } + template auto_ptr &operator=(auto_ptr &) throw() { + return *this; + } + auto_ptr &operator=(auto_ptr_ref r) throw() { return *this; } + ~auto_ptr() throw() {} + auto_ptr(auto_ptr_ref r) throw() : x_(r.y_) {} + template operator auto_ptr_ref() throw() { + auto_ptr_ref r; + r.y_ = x_; + return r; + } + template operator auto_ptr() throw() { return auto_ptr(x_); } + +private: + X *x_; +}; + +template <> class auto_ptr { +public: + typedef void element_type; +}; + +} // namespace _1 + +} // end namespace std + +#endif // INPUTS_MEMORY_H Index: test/clang-tidy/modernize-replace-auto-ptr.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-replace-auto-ptr.cpp @@ -0,0 +1,304 @@ +// RUN: %python %S/check_clang_tidy.py %s modernize-replace-auto-ptr %t -- \ +// RUN: -std=c++11 -I %S/Inputs/modernize-replace-auto-ptr + +// CHECK-FIXES: #include + +#include "memory.h" + +// Instrumentation for auto_ptr_ref test. +struct Base {}; +struct Derived : Base {}; +std::auto_ptr create_derived_ptr(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated, use unique_ptr instead [modernize-replace-auto-ptr] +// CHECK-FIXES: std::unique_ptr create_derived_ptr(); + + +// Test function return values (declaration) +std::auto_ptr f_5(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated +// CHECK-FIXES: std::unique_ptr f_5() + + +// Test function parameters. +void f_6(std::auto_ptr); +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated +// CHECK-FIXES: void f_6(std::unique_ptr); +void f_7(const std::auto_ptr &); +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: auto_ptr is deprecated +// CHECK-FIXES: void f_7(const std::unique_ptr &); + + +// Test on record type fields. +struct A { + std::auto_ptr field; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr field; + + typedef std::auto_ptr int_ptr_type; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: auto_ptr is deprecated + // CHECK-FIXES: typedef std::unique_ptr int_ptr_type; +}; + + +// FIXME: Test template WITH instantiation. +template struct B { + typedef typename std::auto_ptr created_type; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: auto_ptr is deprecated + // CHECK-FIXES: typedef typename std::unique_ptr created_type; + + created_type create() { return std::auto_ptr(new T()); } + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: auto_ptr is deprecated + // CHECK-FIXES: created_type create() { return std::unique_ptr(new T()); } +}; + + +// Test 'using' in a namespace (declaration) +namespace ns_1 { +// Test multiple using declarations. + using std::auto_ptr; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated + // CHECK-FIXES: using std::unique_ptr; + using std::auto_ptr; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated + // CHECK-FIXES: using std::unique_ptr; +} + + +namespace ns_2 { +template struct auto_ptr {}; +} + +void f_1() { + std::auto_ptr a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr a; + + // Check that spaces aren't modified unnecessarily. + std:: auto_ptr b; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: auto_ptr is deprecated + // CHECK-FIXES: std:: unique_ptr b; + std :: auto_ptr < char > c(new char()); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: auto_ptr is deprecated + // CHECK-FIXES: std :: unique_ptr < char > c(new char()); + + // Test construction from a temporary. + std::auto_ptr d = std::auto_ptr(); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr d = std::unique_ptr(); + + typedef std::auto_ptr int_ptr_t; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: auto_ptr is deprecated + // CHECK-FIXES: typedef std::unique_ptr int_ptr_t; + int_ptr_t e(new int()); + + // Test pointers. + std::auto_ptr *f; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr *f; + + // Test 'static' declarations. + static std::auto_ptr g; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated + // CHECK-FIXES: static std::unique_ptr g; + + // Test with cv-qualifiers. + const std::auto_ptr h; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated + // CHECK-FIXES: const std::unique_ptr h; + volatile std::auto_ptr i; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated + // CHECK-FIXES: volatile std::unique_ptr i; + const volatile std::auto_ptr j; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: auto_ptr is deprecated + // CHECK-FIXES: const volatile std::unique_ptr j; + + // Test auto and initializer-list. + auto k = std::auto_ptr{}; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated + // CHECK-FIXES: auto k = std::unique_ptr{}; + std::auto_ptr l{std::auto_ptr()}; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr l{std::unique_ptr()}; + + // Test interlocked auto_ptr. + std::auto_ptr > m; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr > m; + + // Test temporaries. + std::auto_ptr(); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr(); + + // Test void-specialization. + std::auto_ptr n; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr n; + + // Test template WITH instantiation (instantiation). + B o; + std::auto_ptr p(o.create()); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr p(o.create()); + + // Test 'using' in a namespace ("definition"). + ns_1::auto_ptr q; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: auto_ptr is deprecated + // CHECK-FIXES: ns_1::unique_ptr q; + + // Test construction with an 'auto_ptr_ref'. + std::auto_ptr r(create_derived_ptr()); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr r(create_derived_ptr()); +} + +// Test without the nested name specifiers. +void f_2() { + using namespace std; + + auto_ptr a; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: auto_ptr is deprecated + // CHECK-FIXES: unique_ptr a; +} + +// Test using declaration. +void f_3() { + using std::auto_ptr; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated + // CHECK-FIXES: using std::unique_ptr; + + auto_ptr a; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: auto_ptr is deprecated + // CHECK-FIXES: unique_ptr a; +} + +// Test messing-up with macros. +void f_4() { +#define MACRO_1 + std::auto_ptr MACRO_1 p(new char()); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr MACRO_1 p(new char()); +#define MACRO_2 auto_ptr + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated + // CHECK-FIXES: #define MACRO_2 unique_ptr + std::MACRO_2 q; +#define MACRO_3(Type) std::auto_ptr + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: auto_ptr is deprecated + // CHECK-FIXES: #define MACRO_3(Type) std::unique_ptr + MACRO_3(float)r(new float()); +#define MACRO_4 std::auto_ptr + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: auto_ptr is deprecated + // CHECK-FIXES: #define MACRO_4 std::unique_ptr + using MACRO_4; +#undef MACRO_1 +#undef MACRO_2 +#undef MACRO_3 +#undef MACRO_4 +} + +// Test function return values (definition). +std::auto_ptr f_5() + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr f_5() +{ + // Test constructor. + return std::auto_ptr(new char()); + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated + // CHECK-FIXES: return std::unique_ptr(new char()); +} + +// Test that non-std auto_ptr aren't replaced. +void f_8() { + ns_2::auto_ptr a; + using namespace ns_2; + auto_ptr b; +} + +// 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 +void f() { + std::auto_ptr p; +} + +// FIXME: Alias template could be replaced if a matcher existed. +namespace std { +template using aaaaaaaa = auto_ptr; +} + +// We want to avoid replacing 'aaaaaaaa' by unique_ptr here. It's better to +// change the type alias directly. +std::aaaaaaaa d; + + +void takes_ownership_fn(std::auto_ptr x); +// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: auto_ptr is deprecated +// CHECK-FIXES: void takes_ownership_fn(std::unique_ptr x); + +std::auto_ptr get_by_value(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated +// CHECK-FIXES: std::unique_ptr get_by_value(); + +class Wrapper { + public: + std::auto_ptr &get_wrapped(); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + + private: + std::auto_ptr wrapped; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated +}; + +void f() { + std::auto_ptr a, b, c; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr a, b, c; + Wrapper wrapper_a, wrapper_b; + + a = b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::move to transfer ownership + // CHECK-FIXES: a = std::move(b); + + wrapper_a.get_wrapped() = wrapper_b.get_wrapped(); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::move to transfer ownership + // CHECK-FIXES: 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-MESSAGES: :[[@LINE-1]]:22: warning: use std::move to transfer ownership + // CHECK-FIXES: takes_ownership_fn(std::move(c)); + takes_ownership_fn(wrapper_a.get_wrapped()); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::move to transfer ownership + // CHECK-FIXES: takes_ownership_fn(std::move(wrapper_a.get_wrapped())); + + std::auto_ptr d[] = { std::auto_ptr(new int(1)), + std::auto_ptr(new int(2)) }; + // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: auto_ptr is deprecated + // CHECK-MESSAGES: :[[@LINE-3]]:35: warning: auto_ptr is deprecated + // CHECK-MESSAGES: :[[@LINE-3]]:35: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr d[] = { std::unique_ptr(new int(1)), + // CHECK-FIXES-NEXT: std::unique_ptr(new int(2)) }; + std::auto_ptr e = d[0]; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use std::move to transfer ownership + // CHECK: std::unique_ptr e = std::move(d[0]); + + // Test that std::move() is not used when assigning an rvalue + std::auto_ptr f; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr f; + f = std::auto_ptr(new int(0)); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: auto_ptr is deprecated + // CHECK-NEXT: f = std::unique_ptr(new int(0)); + + std::auto_ptr g = get_by_value(); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated + // CHECK-FIXES: std::unique_ptr g = get_by_value(); +}