clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

ReplaceAutoPtrCheck.cpp
Go to the documentation of this file.
1 //===--- ReplaceAutoPtrCheck.cpp - clang-tidy------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "ReplaceAutoPtrCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 #include "clang/Lex/Lexer.h"
15 #include "clang/Lex/Preprocessor.h"
16
17 using namespace clang;
18 using namespace clang::ast_matchers;
19
20 namespace clang {
21 namespace tidy {
22 namespace modernize {
23
24 static const char AutoPtrTokenId[] = "AutoPrTokenId";
25 static const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId";
26
27 /// \brief 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 /// \brief Matcher that finds auto_ptr declarations.
73 static DeclarationMatcher AutoPtrDecl =
74 recordDecl(hasName("auto_ptr"), isFromStdNamespace());
75
76 /// \brief Matches types declared as auto_ptr.
77 static TypeMatcher AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
78
79 /// \brief Matcher that finds expressions that are candidates to be wrapped with
80 /// 'std::move'.
81 ///
82 /// Binds the id \c AutoPtrOwnershipTransferId to the expression.
83 static StatementMatcher MovableArgumentMatcher =
84 expr(allOf(isLValue(), hasType(AutoPtrType)))
85 .bind(AutoPtrOwnershipTransferId);
86
87 /// \brief Creates a matcher that finds the locations of types referring to the
88 /// \c std::auto_ptr() type.
89 ///
90 /// \code
91 /// std::auto_ptr<int> a;
92 /// ^~~~~~~~~~~~~
93 ///
94 /// typedef std::auto_ptr<int> int_ptr_t;
95 /// ^~~~~~~~~~~~~
96 ///
97 /// std::auto_ptr<int> fn(std::auto_ptr<int>);
98 /// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
99 ///
100 /// <etc...>
101 /// \endcode
102 TypeLocMatcher makeAutoPtrTypeLocMatcher() {
103 // Skip elaboratedType() as the named type will match soon thereafter.
104 return typeLoc(loc(qualType(AutoPtrType, unless(elaboratedType()))))
105 .bind(AutoPtrTokenId);
106 }
107
108 /// \brief Creates a matcher that finds the using declarations referring to
109 /// \c std::auto_ptr.
110 ///
111 /// \code
112 /// using std::auto_ptr;
113 /// ^~~~~~~~~~~~~~~~~~~
114 /// \endcode
115 DeclarationMatcher makeAutoPtrUsingDeclMatcher() {
116 return usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(
117 allOf(hasName("auto_ptr"), isFromStdNamespace()))))
118 .bind(AutoPtrTokenId);
119 }
120
121 /// \brief Creates a matcher that finds the \c std::auto_ptr copy-ctor and
122 /// assign-operator expressions.
123 ///
124 /// \c AutoPtrOwnershipTransferId is assigned to the argument of the expression,
125 /// this is the part that has to be wrapped by \c std::move().
126 ///
127 /// \code
128 /// std::auto_ptr<int> i, j;
129 /// i = j;
130 /// ~~~~^
131 /// \endcode
132 StatementMatcher makeTransferOwnershipExprMatcher() {
133 return anyOf(
134 cxxOperatorCallExpr(allOf(hasOverloadedOperatorName("="),
135 callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
136 hasArgument(1, MovableArgumentMatcher))),
137 cxxConstructExpr(allOf(hasType(AutoPtrType), argumentCountIs(1),
138 hasArgument(0, MovableArgumentMatcher))));
139 }
140
141 /// \brief Locates the \c auto_ptr token when it is referred by a \c TypeLoc.
142 ///
143 /// \code
144 /// std::auto_ptr<int> i;
145 /// ^~~~~~~~~~~~~
146 /// \endcode
147 ///
148 /// The caret represents the location returned and the tildes cover the
149 /// parameter \p AutoPtrTypeLoc.
150 ///
151 /// \return An invalid \c SourceLocation if not found, otherwise the location
152 /// of the beginning of the \c auto_ptr token.
153 static SourceLocation locateFromTypeLoc(const TypeLoc *AutoPtrTypeLoc,
154 const SourceManager &SM) {
155 auto TL = AutoPtrTypeLoc->getAs<TemplateSpecializationTypeLoc>();
156 if (TL.isNull())
157 return SourceLocation();
158
159 return TL.getTemplateNameLoc();
160 }
161
162 /// \brief Locates the \c auto_ptr token in using declarations.
163 ///
164 /// \code
165 /// using std::auto_ptr;
166 /// ^
167 /// \endcode
168 ///
169 /// The caret represents the location returned.
170 ///
171 /// \return An invalid \c SourceLocation if not found, otherwise the location
172 /// of the beginning of the \c auto_ptr token.
173 static SourceLocation locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl,
174 const SourceManager &SM) {
175 return UsingAutoPtrDecl->getNameInfo().getBeginLoc();
176 }
177
178 /// \brief Verifies that the token at \p TokenStart is 'auto_ptr'.
179 static bool checkTokenIsAutoPtr(SourceLocation TokenStart,
180 const SourceManager &SM,
181 const LangOptions &LO) {
182 SmallVector<char, 8> Buffer;
183 bool Invalid = false;
184 StringRef Res = Lexer::getSpelling(TokenStart, Buffer, SM, LO, &Invalid);
185
186 return (!Invalid && Res == "auto_ptr");
187 }
188
189 ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name,
190 ClangTidyContext *Context)
191 : ClangTidyCheck(Name, Context),
192 IncludeStyle(IncludeSorter::parseIncludeStyle(
193 Options.get("IncludeStyle", "llvm"))) {}
194
195 void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
196 Options.store(Opts, "IncludeStyle", IncludeSorter::toString(IncludeStyle));
197 }
198
199 void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
200 // Only register the matchers for C++; the functionality currently does not
201 // provide any benefit to other languages, despite being benign.
202 if (getLangOpts().CPlusPlus) {
203 Finder->addMatcher(makeAutoPtrTypeLocMatcher(), this);
204 Finder->addMatcher(makeAutoPtrUsingDeclMatcher(), this);
205 Finder->addMatcher(makeTransferOwnershipExprMatcher(), this);
206 }
207 }
208
209 void ReplaceAutoPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) {
210 // Only register the preprocessor callbacks for C++; the functionality
211 // currently does not provide any benefit to other languages, despite being
212 // benign.
213 if (getLangOpts().CPlusPlus) {
214 Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),
215 Compiler.getLangOpts(), IncludeStyle));
216 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
217 }
218 }
219
220 void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
221 SourceManager &SM = *Result.SourceManager;
222 if (const auto *E =
223 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
224 CharSourceRange Range = Lexer::makeFileCharRange(
225 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
226
227 if (Range.isInvalid())
228 return;
229
230 auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")
231 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
232 << FixItHint::CreateInsertion(Range.getEnd(), ")");
233
234 auto Insertion =
235 Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
236 /*IsAngled=*/true);
237 if (Insertion.hasValue())
238 Diag << Insertion.getValue();
239
240 return;
241 }
242
243 SourceLocation IdentifierLoc;
244 if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
245 IdentifierLoc = locateFromTypeLoc(TL, SM);
246 } else if (const auto *D =
247 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
248 IdentifierLoc = locateFromUsingDecl(D, SM);
249 } else {
250 llvm_unreachable("Bad Callback. No node provided.");
251 }
252
253 if (IdentifierLoc.isMacroID())
254 IdentifierLoc = SM.getSpellingLoc(IdentifierLoc);
255
256 // Ensure that only the 'auto_ptr' token is replaced and not the template
257 // aliases.
258 if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions()))
259 return;
260
261 SourceLocation EndLoc =
262 IdentifierLoc.getLocWithOffset(strlen("auto_ptr") - 1);
263 diag(IdentifierLoc, "auto_ptr is deprecated, use unique_ptr instead")
264 << FixItHint::CreateReplacement(SourceRange(IdentifierLoc, EndLoc),
265 "unique_ptr");
266 }
267
268 } // namespace modernize
269 } // namespace tidy
270 } // namespace clang
clang::tidy::ClangTidyCheck::getLangOpts
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:162
clang::tidy::modernize::locateFromUsingDecl
static SourceLocation locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl, const SourceManager &SM)
Locates the auto_ptr token in using declarations.
Definition: ReplaceAutoPtrCheck.cpp:173
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
clang::tidy::modernize::AutoPtrOwnershipTransferId
static const char AutoPtrOwnershipTransferId[]
Definition: ReplaceAutoPtrCheck.cpp:25
clang::tidy::IncludeSorter::toString
static StringRef toString(IncludeStyle Style)
Definition: IncludeSorter.cpp:290
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:102
ReplaceAutoPtrCheck.h
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:158
clang::tidy::modernize::ReplaceAutoPtrCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register ASTMatchers with Finder.
Definition: ReplaceAutoPtrCheck.cpp:199
clang::tidy::modernize::AutoPtrTokenId
static const char AutoPtrTokenId[]
Definition: ReplaceAutoPtrCheck.cpp:24
clang::tidy::modernize::makeTransferOwnershipExprMatcher
StatementMatcher makeTransferOwnershipExprMatcher()
Creates a matcher that finds the std::auto_ptr copy-ctor and assign-operator expressions.
Definition: ReplaceAutoPtrCheck.cpp:132
SM
SourceManager & SM
Definition: IncludeOrderCheck.cpp:44
clang::tidy::modernize::makeAutoPtrTypeLocMatcher
TypeLocMatcher makeAutoPtrTypeLocMatcher()
Matches declarations whose declaration context is the C++ standard library namespace std...
Definition: ReplaceAutoPtrCheck.cpp:102
clang::tidy::modernize::checkTokenIsAutoPtr
static bool checkTokenIsAutoPtr(SourceLocation TokenStart, const SourceManager &SM, const LangOptions &LO)
Verifies that the token at TokenStart is 'auto_ptr'.
Definition: ReplaceAutoPtrCheck.cpp:179
clang::tidy::modernize::AST_MATCHER
AST_MATCHER(Expr, isLValue)
Matches expressions that are lvalues.
Definition: ReplaceAutoPtrCheck.cpp:36
clang::tidy::OptionsView::store
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidy.cpp:344
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:82
clang::tidy::modernize::makeAutoPtrUsingDeclMatcher
DeclarationMatcher makeAutoPtrUsingDeclMatcher()
Creates a matcher that finds the using declarations referring to std::auto_ptr.
Definition: ReplaceAutoPtrCheck.cpp:115
clang::tidy::modernize::ReplaceAutoPtrCheck::registerPPCallbacks
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
Definition: ReplaceAutoPtrCheck.cpp:209
clang::tidy::IncludeSorter
Definition: IncludeSorter.h:23
clang::tidy::modernize::ReplaceAutoPtrCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: ReplaceAutoPtrCheck.cpp:220
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:35
clang::tidy::modernize::ReplaceAutoPtrCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: ReplaceAutoPtrCheck.cpp:195
Context
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:124
clang::tidy::IncludeInserter
Definition: IncludeInserter.h:47
clang::tidy::modernize::locateFromTypeLoc
static SourceLocation locateFromTypeLoc(const TypeLoc *AutoPtrTypeLoc, const SourceManager &SM)
Locates the auto_ptr token when it is referred by a TypeLoc.
Definition: ReplaceAutoPtrCheck.cpp:153
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidy.cpp:323
Result
const NamedDecl * Result
Definition: USRFinder.cpp:121