clang-tools 24.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 const auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace());
53 const auto AutoPtrType =
54 hasCanonicalType(recordType(hasDeclaration(AutoPtrDecl)));
55
56 // std::auto_ptr<int> a;
57 // ^~~~~~~~~~~~~
58 //
59 // typedef std::auto_ptr<int> int_ptr_t;
60 // ^~~~~~~~~~~~~
61 //
62 // std::auto_ptr<int> fn(std::auto_ptr<int>);
63 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
64 Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType))).bind(AutoPtrTokenId),
65 this);
66
67 // using std::auto_ptr;
68 // ^~~~~~~~~~~~~~~~~~~
69 Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(
70 hasName("auto_ptr"), isInStdNamespace()))))
71 .bind(AutoPtrTokenId),
72 this);
73
74 // Find ownership transfers via copy construction and assignment.
75 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped
76 // into std::move().
77 // std::auto_ptr<int> i, j;
78 // i = j;
79 // ~~~~^
80 const auto MovableArgumentMatcher =
81 expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
82
83 Finder->addMatcher(
84 cxxOperatorCallExpr(hasOverloadedOperatorName("="),
85 callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
86 hasArgument(1, MovableArgumentMatcher)),
87 this);
88 Finder->addMatcher(
89 traverse(TK_AsIs,
90 cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),
91 hasArgument(0, MovableArgumentMatcher))),
92 this);
93}
94
95void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM,
96 Preprocessor *PP,
97 Preprocessor *ModuleExpanderPP) {
98 Inserter.registerPreprocessor(PP);
99}
100
101void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
102 const SourceManager &SM = *Result.SourceManager;
103 if (const auto *E =
104 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
105 const CharSourceRange Range = Lexer::makeFileCharRange(
106 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
107
108 if (Range.isInvalid())
109 return;
110
111 const auto Diag =
112 diag(Range.getBegin(), "use std::move to transfer ownership")
113 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
114 << FixItHint::CreateInsertion(Range.getEnd(), ")")
115 << Inserter.createMainFileIncludeInsertion("<utility>");
116
117 return;
118 }
119
120 SourceLocation AutoPtrLoc;
121 if (const auto *PTL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
122 auto TL = *PTL;
123 if (const auto QTL = TL.getAs<QualifiedTypeLoc>())
124 TL = QTL.getUnqualifiedLoc();
125 // std::auto_ptr<int> i;
126 // ^
127 if (const auto Loc = TL.getAs<TemplateSpecializationTypeLoc>())
128 AutoPtrLoc = Loc.getTemplateNameLoc();
129 } else if (const auto *D =
130 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
131 // using std::auto_ptr;
132 // ^
133 AutoPtrLoc = D->getNameInfo().getBeginLoc();
134 } else {
135 llvm_unreachable("Bad Callback. No node provided.");
136 }
137
138 if (AutoPtrLoc.isMacroID())
139 AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);
140
141 // Ensure that only the 'auto_ptr' token is replaced and not the template
142 // aliases.
143 if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=
144 "auto_ptr")
145 return;
146
147 const SourceLocation EndLoc =
148 AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);
149 diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")
150 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),
151 "unique_ptr");
152}
153
154} // 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