clang-tools  11.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(Options.getLocalOrGlobal("IncludeStyle",
78  utils::IncludeSorter::IS_LLVM)) {}
79 
80 void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
81  Options.store(Opts, "IncludeStyle", IncludeStyle);
82 }
83 
84 void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
85  auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isFromStdNamespace());
86  auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
87 
88  // std::auto_ptr<int> a;
89  // ^~~~~~~~~~~~~
90  //
91  // typedef std::auto_ptr<int> int_ptr_t;
92  // ^~~~~~~~~~~~~
93  //
94  // std::auto_ptr<int> fn(std::auto_ptr<int>);
95  // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
96  Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
97  // Skip elaboratedType() as the named
98  // type will match soon thereafter.
99  unless(elaboratedType()))))
100  .bind(AutoPtrTokenId),
101  this);
102 
103  // using std::auto_ptr;
104  // ^~~~~~~~~~~~~~~~~~~
105  Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
106  hasName("auto_ptr"), isFromStdNamespace()))))
107  .bind(AutoPtrTokenId),
108  this);
109 
110  // Find ownership transfers via copy construction and assignment.
111  // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
112  // into std::move().
113  // std::auto_ptr<int> i, j;
114  // i = j;
115  // ~~~~^
116  auto MovableArgumentMatcher =
117  expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
118 
119  Finder->addMatcher(
120  cxxOperatorCallExpr(hasOverloadedOperatorName("="),
121  callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
122  hasArgument(1, MovableArgumentMatcher)),
123  this);
124  Finder->addMatcher(
125  traverse(ast_type_traits::TK_AsIs,
126  cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),
127  hasArgument(0, MovableArgumentMatcher))),
128  this);
129 }
130 
131 void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM,
132  Preprocessor *PP,
133  Preprocessor *ModuleExpanderPP) {
134  Inserter = std::make_unique<utils::IncludeInserter>(SM, getLangOpts(),
135  IncludeStyle);
136  PP->addPPCallbacks(Inserter->CreatePPCallbacks());
137 }
138 
139 void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
140  SourceManager &SM = *Result.SourceManager;
141  if (const auto *E =
142  Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
143  CharSourceRange Range = Lexer::makeFileCharRange(
144  CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
145 
146  if (Range.isInvalid())
147  return;
148 
149  auto Diag =
150  diag(Range.getBegin(), "use std::move to transfer ownership")
151  << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
152  << FixItHint::CreateInsertion(Range.getEnd(), ")")
153  << Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
154  /*IsAngled=*/true);
155 
156  return;
157  }
158 
159  SourceLocation AutoPtrLoc;
160  if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
161  // std::auto_ptr<int> i;
162  // ^
163  if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
164  AutoPtrLoc = Loc.getTemplateNameLoc();
165  } else if (const auto *D =
166  Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
167  // using std::auto_ptr;
168  // ^
169  AutoPtrLoc = D->getNameInfo().getBeginLoc();
170  } else {
171  llvm_unreachable("Bad Callback. No node provided.");
172  }
173 
174  if (AutoPtrLoc.isMacroID())
175  AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);
176 
177  // Ensure that only the 'auto_ptr' token is replaced and not the template
178  // aliases.
179  if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=
180  "auto_ptr")
181  return;
182 
183  SourceLocation EndLoc =
184  AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);
185  diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")
186  << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),
187  "unique_ptr");
188 }
189 
190 } // namespace modernize
191 } // namespace tidy
192 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::ast_matchers
Definition: AbseilMatcher.h:14
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::ast_matchers::AST_MATCHER
AST_MATCHER(Expr, isMacroID)
Definition: PreferIsaOrDynCastInConditionalsCheck.cpp:19
ReplaceAutoPtrCheck.h
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:29
Info
FunctionInfo Info
Definition: FunctionSizeCheck.cpp:120
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
Loc
SourceLocation Loc
'#' location in the include directive
Definition: IncludeOrderCheck.cpp:37