1 //===--- ReplaceAutoPtrCheck.cpp - clang-tidy------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "ReplaceAutoPtrCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/Lexer.h"
14 #include "clang/Lex/Preprocessor.h"
16 using namespace clang
;
17 using namespace clang::ast_matchers
;
19 namespace clang::tidy::modernize
{
22 static const char AutoPtrTokenId
[] = "AutoPrTokenId";
23 static const char AutoPtrOwnershipTransferId
[] = "AutoPtrOwnershipTransferId";
25 /// Matches expressions that are lvalues.
27 /// In the following example, a[0] matches expr(isLValue()):
32 /// b = "this string won't match";
34 AST_MATCHER(Expr
, isLValue
) { return Node
.getValueKind() == VK_LValue
; }
38 ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name
,
39 ClangTidyContext
*Context
)
40 : ClangTidyCheck(Name
, Context
),
41 Inserter(Options
.getLocalOrGlobal("IncludeStyle",
42 utils::IncludeSorter::IS_LLVM
),
43 areDiagsSelfContained()) {}
45 void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
46 Options
.store(Opts
, "IncludeStyle", Inserter
.getStyle());
49 void ReplaceAutoPtrCheck::registerMatchers(MatchFinder
*Finder
) {
50 auto AutoPtrDecl
= recordDecl(hasName("auto_ptr"), isInStdNamespace());
51 auto AutoPtrType
= qualType(hasDeclaration(AutoPtrDecl
));
53 // std::auto_ptr<int> a;
56 // typedef std::auto_ptr<int> int_ptr_t;
59 // std::auto_ptr<int> fn(std::auto_ptr<int>);
60 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
61 Finder
->addMatcher(typeLoc(loc(qualType(AutoPtrType
,
62 // Skip elaboratedType() as the named
63 // type will match soon thereafter.
64 unless(elaboratedType()))))
65 .bind(AutoPtrTokenId
),
68 // using std::auto_ptr;
69 // ^~~~~~~~~~~~~~~~~~~
70 Finder
->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
71 hasName("auto_ptr"), isInStdNamespace()))))
72 .bind(AutoPtrTokenId
),
75 // Find ownership transfers via copy construction and assignment.
76 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
78 // std::auto_ptr<int> i, j;
81 auto MovableArgumentMatcher
=
82 expr(isLValue(), hasType(AutoPtrType
)).bind(AutoPtrOwnershipTransferId
);
85 cxxOperatorCallExpr(hasOverloadedOperatorName("="),
86 callee(cxxMethodDecl(ofClass(AutoPtrDecl
))),
87 hasArgument(1, MovableArgumentMatcher
)),
91 cxxConstructExpr(hasType(AutoPtrType
), argumentCountIs(1),
92 hasArgument(0, MovableArgumentMatcher
))),
96 void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager
&SM
,
98 Preprocessor
*ModuleExpanderPP
) {
99 Inserter
.registerPreprocessor(PP
);
102 void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult
&Result
) {
103 SourceManager
&SM
= *Result
.SourceManager
;
105 Result
.Nodes
.getNodeAs
<Expr
>(AutoPtrOwnershipTransferId
)) {
106 CharSourceRange Range
= Lexer::makeFileCharRange(
107 CharSourceRange::getTokenRange(E
->getSourceRange()), SM
, LangOptions());
109 if (Range
.isInvalid())
112 auto Diag
= diag(Range
.getBegin(), "use std::move to transfer ownership")
113 << FixItHint::CreateInsertion(Range
.getBegin(), "std::move(")
114 << FixItHint::CreateInsertion(Range
.getEnd(), ")")
115 << Inserter
.createMainFileIncludeInsertion("<utility>");
120 SourceLocation AutoPtrLoc
;
121 if (const auto *TL
= Result
.Nodes
.getNodeAs
<TypeLoc
>(AutoPtrTokenId
)) {
122 // std::auto_ptr<int> i;
124 if (auto Loc
= TL
->getAs
<TemplateSpecializationTypeLoc
>())
125 AutoPtrLoc
= Loc
.getTemplateNameLoc();
126 } else if (const auto *D
=
127 Result
.Nodes
.getNodeAs
<UsingDecl
>(AutoPtrTokenId
)) {
128 // using std::auto_ptr;
130 AutoPtrLoc
= D
->getNameInfo().getBeginLoc();
132 llvm_unreachable("Bad Callback. No node provided.");
135 if (AutoPtrLoc
.isMacroID())
136 AutoPtrLoc
= SM
.getSpellingLoc(AutoPtrLoc
);
138 // Ensure that only the 'auto_ptr' token is replaced and not the template
140 if (StringRef(SM
.getCharacterData(AutoPtrLoc
), strlen("auto_ptr")) !=
144 SourceLocation EndLoc
=
145 AutoPtrLoc
.getLocWithOffset(strlen("auto_ptr") - 1);
146 diag(AutoPtrLoc
, "auto_ptr is deprecated, use unique_ptr instead")
147 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc
, EndLoc
),
151 } // namespace clang::tidy::modernize