clang-tools  3.8.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 /// \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)))
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
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,
191  : ClangTidyCheck(Name, Context),
192  IncludeStyle(IncludeSorter::parseIncludeStyle(
193  Options.get("IncludeStyle", "llvm"))) {}
194 
196  Options.store(Opts, "IncludeStyle", IncludeSorter::toString(IncludeStyle));
197 }
198 
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
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:162
static SourceLocation locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl, const SourceManager &SM)
Locates the auto_ptr token in using declarations.
StringHandle Name
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
static const char AutoPtrOwnershipTransferId[]
static StringRef toString(IncludeStyle Style)
Base class for all clang-tidy checks.
Definition: ClangTidy.h:102
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register ASTMatchers with Finder.
static const char AutoPtrTokenId[]
StatementMatcher makeTransferOwnershipExprMatcher()
Creates a matcher that finds the std::auto_ptr copy-ctor and assign-operator expressions.
SourceManager & SM
TypeLocMatcher makeAutoPtrTypeLocMatcher()
Matches declarations whose declaration context is the C++ standard library namespace std...
static bool checkTokenIsAutoPtr(SourceLocation TokenStart, const SourceManager &SM, const LangOptions &LO)
Verifies that the token at TokenStart is 'auto_ptr'.
AST_MATCHER(Expr, isLValue)
Matches expressions that are lvalues.
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
std::map< std::string, std::string > OptionMap
DeclarationMatcher makeAutoPtrUsingDeclMatcher()
Creates a matcher that finds the using declarations referring to std::auto_ptr.
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
CharSourceRange Range
SourceRange for the file name.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static SourceLocation locateFromTypeLoc(const TypeLoc *AutoPtrTypeLoc, const SourceManager &SM)
Locates the auto_ptr token when it is referred by a TypeLoc.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidy.cpp:323
const NamedDecl * Result
Definition: USRFinder.cpp:121