1//===--- ReplaceAutoPtrCheck.cpp - clang-tidy------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
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"
15
16using namespace clang;
17using namespace clang::ast_matchers;
18
19namespace clang::tidy::modernize {
20
21namespace {
22static const char AutoPtrTokenId[] = "AutoPrTokenId";
23static const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId";
24
25/// Matches expressions that are lvalues.
26///
27/// In the following example, a[0] matches expr(isLValue()):
28/// \code
29/// std::string a[2];
30/// std::string b;
31/// b = a[0];
32/// b = "this string won't match";
33/// \endcode
34AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; }
35
36} // namespace
37
38ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name,
39 ClangTidyContext *Context)
40 : ClangTidyCheck(Name, Context),
41 Inserter(Options.getLocalOrGlobal(LocalName: "IncludeStyle",
42 Default: utils::IncludeSorter::IS_LLVM),
43 areDiagsSelfContained()) {}
44
45void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
46 Options.store(Options&: Opts, LocalName: "IncludeStyle", Value: Inserter.getStyle());
47}
48
49void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
50 auto AutoPtrDecl = recordDecl(hasName(Name: "auto_ptr"), isInStdNamespace());
51 auto AutoPtrType = qualType(hasDeclaration(InnerMatcher: AutoPtrDecl));
52
53 // std::auto_ptr<int> a;
54 // ^~~~~~~~~~~~~
55 //
56 // typedef std::auto_ptr<int> int_ptr_t;
57 // ^~~~~~~~~~~~~
58 //
59 // std::auto_ptr<int> fn(std::auto_ptr<int>);
60 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
61 Finder->addMatcher(NodeMatch: typeLoc(loc(InnerMatcher: qualType(AutoPtrType,
62 // Skip elaboratedType() as the named
63 // type will match soon thereafter.
64 unless(elaboratedType()))))
65 .bind(ID: AutoPtrTokenId),
66 Action: this);
67
68 // using std::auto_ptr;
69 // ^~~~~~~~~~~~~~~~~~~
70 Finder->addMatcher(NodeMatch: usingDecl(hasAnyUsingShadowDecl(InnerMatcher: hasTargetDecl(InnerMatcher: namedDecl(
71 hasName(Name: "auto_ptr"), isInStdNamespace()))))
72 .bind(ID: AutoPtrTokenId),
73 Action: this);
74
75 // Find ownership transfers via copy construction and assignment.
76 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
77 // into std::move().
78 // std::auto_ptr<int> i, j;
79 // i = j;
80 // ~~~~^
81 auto MovableArgumentMatcher =
82 expr(isLValue(), hasType(InnerMatcher: AutoPtrType)).bind(ID: AutoPtrOwnershipTransferId);
83
84 Finder->addMatcher(
85 NodeMatch: cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "="),
86 callee(InnerMatcher: cxxMethodDecl(ofClass(InnerMatcher: AutoPtrDecl))),
87 hasArgument(N: 1, InnerMatcher: MovableArgumentMatcher)),
88 Action: this);
89 Finder->addMatcher(
90 NodeMatch: traverse(TK: TK_AsIs,
91 InnerMatcher: cxxConstructExpr(hasType(InnerMatcher: AutoPtrType), argumentCountIs(N: 1),
92 hasArgument(N: 0, InnerMatcher: MovableArgumentMatcher))),
93 Action: this);
94}
95
96void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM,
97 Preprocessor *PP,
98 Preprocessor *ModuleExpanderPP) {
99 Inserter.registerPreprocessor(PP);
100}
101
102void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
103 SourceManager &SM = *Result.SourceManager;
104 if (const auto *E =
105 Result.Nodes.getNodeAs<Expr>(ID: AutoPtrOwnershipTransferId)) {
106 CharSourceRange Range = Lexer::makeFileCharRange(
107 Range: CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOpts: LangOptions());
108
109 if (Range.isInvalid())
110 return;
111
112 auto Diag = diag(Loc: Range.getBegin(), Description: "use std::move to transfer ownership")
113 << FixItHint::CreateInsertion(InsertionLoc: Range.getBegin(), Code: "std::move(")
114 << FixItHint::CreateInsertion(InsertionLoc: Range.getEnd(), Code: ")")
115 << Inserter.createMainFileIncludeInsertion(Header: "<utility>");
116
117 return;
118 }
119
120 SourceLocation AutoPtrLoc;
121 if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(ID: AutoPtrTokenId)) {
122 // std::auto_ptr<int> i;
123 // ^
124 if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
125 AutoPtrLoc = Loc.getTemplateNameLoc();
126 } else if (const auto *D =
127 Result.Nodes.getNodeAs<UsingDecl>(ID: AutoPtrTokenId)) {
128 // using std::auto_ptr;
129 // ^
130 AutoPtrLoc = D->getNameInfo().getBeginLoc();
131 } else {
132 llvm_unreachable("Bad Callback. No node provided.");
133 }
134
135 if (AutoPtrLoc.isMacroID())
136 AutoPtrLoc = SM.getSpellingLoc(Loc: AutoPtrLoc);
137
138 // Ensure that only the 'auto_ptr' token is replaced and not the template
139 // aliases.
140 if (StringRef(SM.getCharacterData(SL: AutoPtrLoc), strlen(s: "auto_ptr")) !=
141 "auto_ptr")
142 return;
143
144 SourceLocation EndLoc =
145 AutoPtrLoc.getLocWithOffset(Offset: strlen(s: "auto_ptr") - 1);
146 diag(Loc: AutoPtrLoc, Description: "auto_ptr is deprecated, use unique_ptr instead")
147 << FixItHint::CreateReplacement(RemoveRange: SourceRange(AutoPtrLoc, EndLoc),
148 Code: "unique_ptr");
149}
150
151} // namespace clang::tidy::modernize
152

source code of clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp