clang-tools 6.0.0

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 ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name,
73 ClangTidyContext *Context)
74 : ClangTidyCheck(Name, Context),
75 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
76 Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
77
78 void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
79 Options.store(Opts, "IncludeStyle",
80 utils::IncludeSorter::toString(IncludeStyle));
81 }
82
83 void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
84 // Only register the matchers for C++; the functionality currently does not
85 // provide any benefit to other languages, despite being benign.
86 if (!getLangOpts().CPlusPlus)
87 return;
88
89 auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isFromStdNamespace());
90 auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
91
92 // std::auto_ptr<int> a;
93 // ^~~~~~~~~~~~~
94 //
95 // typedef std::auto_ptr<int> int_ptr_t;
96 // ^~~~~~~~~~~~~
97 //
98 // std::auto_ptr<int> fn(std::auto_ptr<int>);
99 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
100 Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
101 // Skip elaboratedType() as the named
102 // type will match soon thereafter.
103 unless(elaboratedType()))))
104 .bind(AutoPtrTokenId),
105 this);
106
107 // using std::auto_ptr;
108 // ^~~~~~~~~~~~~~~~~~~
109 Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(allOf(
110 hasName("auto_ptr"), isFromStdNamespace()))))
111 .bind(AutoPtrTokenId),
112 this);
113
114 // Find ownership transfers via copy construction and assignment.
115 // AutoPtrOwnershipTransferId is bound to the the part that has to be wrapped
116 // into std::move().
117 // std::auto_ptr<int> i, j;
118 // i = j;
119 // ~~~~^
120 auto MovableArgumentMatcher =
121 expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
122
123 Finder->addMatcher(
124 cxxOperatorCallExpr(hasOverloadedOperatorName("="),
125 callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
126 hasArgument(1, MovableArgumentMatcher)),
127 this);
128 Finder->addMatcher(cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),
129 hasArgument(0, MovableArgumentMatcher)),
130 this);
131 }
132
133 void ReplaceAutoPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) {
134 // Only register the preprocessor callbacks for C++; the functionality
135 // currently does not provide any benefit to other languages, despite being
136 // benign.
137 if (!getLangOpts().CPlusPlus)
138 return;
139 Inserter.reset(new utils::IncludeInserter(
140 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
141 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
142 }
143
144 void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
145 SourceManager &SM = *Result.SourceManager;
146 if (const auto *E =
147 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
148 CharSourceRange Range = Lexer::makeFileCharRange(
149 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
150
151 if (Range.isInvalid())
152 return;
153
154 auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")
155 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
156 << FixItHint::CreateInsertion(Range.getEnd(), ")");
157
158 if (auto Fix =
159 Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
160 /*IsAngled=*/true))
161 Diag << *Fix;
162
163 return;
164 }
165
166 SourceLocation AutoPtrLoc;
167 if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
168 // std::auto_ptr<int> i;
169 // ^
170 if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
171 AutoPtrLoc = Loc.getTemplateNameLoc();
172 } else if (const auto *D =
173 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
174 // using std::auto_ptr;
175 // ^
176 AutoPtrLoc = D->getNameInfo().getBeginLoc();
177 } else {
178 llvm_unreachable("Bad Callback. No node provided.");
179 }
180
181 if (AutoPtrLoc.isMacroID())
182 AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);
183
184 // Ensure that only the 'auto_ptr' token is replaced and not the template
185 // aliases.
186 if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=
187 "auto_ptr")
188 return;
189
190 SourceLocation EndLoc =
191 AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);
192 diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")
193 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),
194 "unique_ptr");
195 }
196
197 } // namespace modernize
198 } // namespace tidy
199 } // namespace clang
Loc
SourceLocation Loc
&#39;#&#39; location in the include directive
Definition: IncludeOrderCheck.cpp:36
clang::ast_matchers
Definition: ClangTidyDiagnosticConsumer.h:27
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:449
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
clang::tidy::ClangTidyCheck::getLangOpts
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
clang::tidy::utils::IncludeSorter::toString
static StringRef toString(IncludeStyle Style)
Converts IncludeStyle to string representation.
Definition: IncludeSorter.cpp:284
ReplaceAutoPtrCheck.h
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:183
clang::tidy::modernize::ReplaceAutoPtrCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:99
clang::tidy::modernize::ReplaceAutoPtrCheck::registerPPCallbacks
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
Info
FunctionInfo Info
Definition: FunctionSizeCheck.cpp:84
clang
Definition: AndroidTidyModule.cpp:28
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.
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:37
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...
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))
clang::ast_matchers::AST_MATCHER
AST_MATCHER(VarDecl, isAsm)
Definition: NoAssemblerCheck.cpp:18
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:416