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