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