clang-tools 22.0.0git
ReplaceAutoPtrCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
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
16using namespace clang;
17using namespace clang::ast_matchers;
18
19namespace clang::tidy::modernize {
20
21static constexpr char AutoPtrTokenId[] = "AutoPrTokenId";
22static constexpr char AutoPtrOwnershipTransferId[] =
23 "AutoPtrOwnershipTransferId";
24
25namespace {
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
36AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; }
37
38} // namespace
39
41 ClangTidyContext *Context)
42 : ClangTidyCheck(Name, Context),
43 Inserter(Options.getLocalOrGlobal("IncludeStyle",
44 utils::IncludeSorter::IS_LLVM),
45 areDiagsSelfContained()) {}
46
48 Options.store(Opts, "IncludeStyle", Inserter.getStyle());
49}
50
51void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
52 auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace());
53 auto AutoPtrType = hasCanonicalType(recordType(hasDeclaration(AutoPtrDecl)));
54
55 // std::auto_ptr<int> a;
56 // ^~~~~~~~~~~~~
57 //
58 // typedef std::auto_ptr<int> int_ptr_t;
59 // ^~~~~~~~~~~~~
60 //
61 // std::auto_ptr<int> fn(std::auto_ptr<int>);
62 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
63 Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType))).bind(AutoPtrTokenId),
64 this);
65
66 // using std::auto_ptr;
67 // ^~~~~~~~~~~~~~~~~~~
68 Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
69 hasName("auto_ptr"), isInStdNamespace()))))
70 .bind(AutoPtrTokenId),
71 this);
72
73 // Find ownership transfers via copy construction and assignment.
74 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
75 // into std::move().
76 // std::auto_ptr<int> i, j;
77 // i = j;
78 // ~~~~^
79 auto MovableArgumentMatcher =
80 expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
81
82 Finder->addMatcher(
83 cxxOperatorCallExpr(hasOverloadedOperatorName("="),
84 callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
85 hasArgument(1, MovableArgumentMatcher)),
86 this);
87 Finder->addMatcher(
88 traverse(TK_AsIs,
89 cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),
90 hasArgument(0, MovableArgumentMatcher))),
91 this);
92}
93
94void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM,
95 Preprocessor *PP,
96 Preprocessor *ModuleExpanderPP) {
97 Inserter.registerPreprocessor(PP);
98}
99
100void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
101 const SourceManager &SM = *Result.SourceManager;
102 if (const auto *E =
103 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
104 const CharSourceRange Range = Lexer::makeFileCharRange(
105 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
106
107 if (Range.isInvalid())
108 return;
109
110 auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")
111 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
112 << FixItHint::CreateInsertion(Range.getEnd(), ")")
113 << Inserter.createMainFileIncludeInsertion("<utility>");
114
115 return;
116 }
117
118 SourceLocation AutoPtrLoc;
119 if (const auto *PTL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
120 auto TL = *PTL;
121 if (auto QTL = TL.getAs<QualifiedTypeLoc>())
122 TL = QTL.getUnqualifiedLoc();
123 // std::auto_ptr<int> i;
124 // ^
125 if (auto Loc = TL.getAs<TemplateSpecializationTypeLoc>())
126 AutoPtrLoc = Loc.getTemplateNameLoc();
127 } else if (const auto *D =
128 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
129 // using std::auto_ptr;
130 // ^
131 AutoPtrLoc = D->getNameInfo().getBeginLoc();
132 } else {
133 llvm_unreachable("Bad Callback. No node provided.");
134 }
135
136 if (AutoPtrLoc.isMacroID())
137 AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);
138
139 // Ensure that only the 'auto_ptr' token is replaced and not the template
140 // aliases.
141 if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=
142 "auto_ptr")
143 return;
144
145 const SourceLocation EndLoc =
146 AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);
147 diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")
148 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),
149 "unique_ptr");
150}
151
152} // namespace clang::tidy::modernize
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
static constexpr char AutoPtrOwnershipTransferId[]
static constexpr char AutoPtrTokenId[]
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringMap< ClangTidyValue > OptionMap