clang-tools 10.0.0

ReplaceAutoPtrCheck.cpp
Go to the documentation of this file.
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
16 using namespace clang;
17 using namespace clang::ast_matchers;
18
19 namespace clang {
20 namespace tidy {
21 namespace modernize {
22
23 namespace {
24 static const char AutoPtrTokenId[] = "AutoPrTokenId";
25 static const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId";
26
27 /// Matches expressions that are lvalues.
28 ///
29 /// In the following example, a[0] matches expr(isLValue()):
30 /// \code
31 /// std::string a[2];
32 /// std::string b;
33 /// b = a[0];
34 /// b = "this string won't match";
35 /// \endcode
36 AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; }
37
38 /// Matches declarations whose declaration context is the C++ standard library
39 /// namespace std.
40 ///
41 /// Note that inline namespaces are silently ignored during the lookup since
42 /// both libstdc++ and libc++ are known to use them for versioning purposes.
43 ///
44 /// Given:
45 /// \code
46 /// namespace ns {
47 /// struct my_type {};
48 /// using namespace std;
49 /// }
50 ///
51 /// using std::vector;
52 /// using ns:my_type;
53 /// using ns::list;
54 /// \code
55 ///
56 /// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(isFromStdNamespace())))
57 /// matches "using std::vector" and "using ns::list".
58 AST_MATCHER(Decl, isFromStdNamespace) {
59 const DeclContext *D = Node.getDeclContext();
60
61 while (D->isInlineNamespace())
62 D = D->getParent();
63
64 if (!D->isNamespace() || !D->getParent()->isTranslationUnit())
65 return false;
66
67 const IdentifierInfo *Info = cast<NamespaceDecl>(D)->getIdentifier();
68
69 return (Info && Info->isStr("std"));
70 }
71
72 } // namespace
73
74 ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name,
75 ClangTidyContext *Context)
76 : ClangTidyCheck(Name, Context),
77 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
78 Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
79
80 void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
81 Options.store(Opts, "IncludeStyle",
82 utils::IncludeSorter::toString(IncludeStyle));
83 }
84
85 void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
86 // Only register the matchers for C++; the functionality currently does not
87 // provide any benefit to other languages, despite being benign.
88 if (!getLangOpts().CPlusPlus)
89 return;
90
91 auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isFromStdNamespace());
92 auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
93
94 // std::auto_ptr<int> a;
95 // ^~~~~~~~~~~~~
96 //
97 // typedef std::auto_ptr<int> int_ptr_t;
98 // ^~~~~~~~~~~~~
99 //
100 // std::auto_ptr<int> fn(std::auto_ptr<int>);
101 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
102 Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
103 // Skip elaboratedType() as the named
104 // type will match soon thereafter.
105 unless(elaboratedType()))))
106 .bind(AutoPtrTokenId),
107 this);
108
109 // using std::auto_ptr;
110 // ^~~~~~~~~~~~~~~~~~~
111 Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
112 hasName("auto_ptr"), isFromStdNamespace()))))
113 .bind(AutoPtrTokenId),
114 this);
115
116 // Find ownership transfers via copy construction and assignment.
117 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
118 // into std::move().
119 // std::auto_ptr<int> i, j;
120 // i = j;
121 // ~~~~^
122 auto MovableArgumentMatcher =
123 expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
124
125 Finder->addMatcher(
126 cxxOperatorCallExpr(hasOverloadedOperatorName("="),
127 callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
128 hasArgument(1, MovableArgumentMatcher)),
129 this);
130 Finder->addMatcher(cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),
131 hasArgument(0, MovableArgumentMatcher)),
132 this);
133 }
134
135 void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM,
136 Preprocessor *PP,
137 Preprocessor *ModuleExpanderPP) {
138 // Only register the preprocessor callbacks for C++; the functionality
139 // currently does not provide any benefit to other languages, despite being
140 // benign.
141 if (!getLangOpts().CPlusPlus)
142 return;
143 Inserter = std::make_unique<utils::IncludeInserter>(SM, getLangOpts(),
144 IncludeStyle);
145 PP->addPPCallbacks(Inserter->CreatePPCallbacks());
146 }
147
148 void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
149 SourceManager &SM = *Result.SourceManager;
150 if (const auto *E =
151 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
152 CharSourceRange Range = Lexer::makeFileCharRange(
153 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
154
155 if (Range.isInvalid())
156 return;
157
158 auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")
159 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
160 << FixItHint::CreateInsertion(Range.getEnd(), ")");
161
162 if (auto Fix =
163 Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
164 /*IsAngled=*/true))
165 Diag << *Fix;
166
167 return;
168 }
169
170 SourceLocation AutoPtrLoc;
171 if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
172 // std::auto_ptr<int> i;
173 // ^
174 if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
175 AutoPtrLoc = Loc.getTemplateNameLoc();
176 } else if (const auto *D =
177 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
178 // using std::auto_ptr;
179 // ^
180 AutoPtrLoc = D->getNameInfo().getBeginLoc();
181 } else {
182 llvm_unreachable("Bad Callback. No node provided.");
183 }
184
185 if (AutoPtrLoc.isMacroID())
186 AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);
187
188 // Ensure that only the 'auto_ptr' token is replaced and not the template
189 // aliases.
190 if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=
191 "auto_ptr")
192 return;
193
194 SourceLocation EndLoc =
195 AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);
196 diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")
197 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),
198 "unique_ptr");
199 }
200
201 } // namespace modernize
202 } // namespace tidy
203 } // namespace clang
Loc
SourceLocation Loc
&#39;#&#39; location in the include directive
Definition: IncludeOrderCheck.cpp:37
clang::ast_matchers
Definition: AbseilMatcher.h:14
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:93
clang::ast_matchers::AST_MATCHER
AST_MATCHER(Expr, isMacroID)
Definition: PreferIsaOrDynCastInConditionalsCheck.cpp:18
clang::tidy::cppcoreguidelines::toString
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
Definition: SpecialMemberFunctionsCheck.cpp:58
ReplaceAutoPtrCheck.h
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::getTokenRange
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:227
Info
FunctionInfo Info
Definition: FunctionSizeCheck.cpp:120
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:28
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
E
const Expr * E
Definition: AvoidBindCheck.cpp:82
Fix
static cl::opt< bool > Fix("fix", cl::desc(R"( Apply suggested fixes. Without -fix-errors clang-tidy will bail out if any compilation errors were found. )"), cl::init(false), cl::cat(ClangTidyCategory))