clang-tools  15.0.0git
UniqueptrResetReleaseCheck.cpp
Go to the documentation of this file.
1 //===--- UniqueptrResetReleaseCheck.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 
10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "clang/Lex/Lexer.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace misc {
18 
19 UniqueptrResetReleaseCheck::UniqueptrResetReleaseCheck(
20  StringRef Name, ClangTidyContext *Context)
21  : ClangTidyCheck(Name, Context),
22  Inserter(Options.getLocalOrGlobal("IncludeStyle",
23  utils::IncludeSorter::IS_LLVM),
24  areDiagsSelfContained()) {}
25 
28  Options.store(Opts, "IncludeStyle", Inserter.getStyle());
29 }
30 
32  const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
33  Inserter.registerPreprocessor(PP);
34 }
35 
37  Finder->addMatcher(
38  cxxMemberCallExpr(
39  callee(memberExpr(
40  member(cxxMethodDecl(
41  hasName("reset"),
42  ofClass(cxxRecordDecl(hasName("::std::unique_ptr"),
43  decl().bind("left_class"))))))
44  .bind("reset_member")),
45  hasArgument(
46  0, ignoringParenImpCasts(cxxMemberCallExpr(
47  on(expr().bind("right")),
48  callee(memberExpr(member(cxxMethodDecl(
49  hasName("release"),
50  ofClass(cxxRecordDecl(
51  hasName("::std::unique_ptr"),
52  decl().bind("right_class"))))))
53  .bind("release_member"))))))
54  .bind("reset_call"),
55  this);
56 }
57 
58 namespace {
59 const Type *getDeleterForUniquePtr(const MatchFinder::MatchResult &Result,
60  StringRef ID) {
61  const auto *Class =
62  Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(ID);
63  if (!Class)
64  return nullptr;
65  auto DeleterArgument = Class->getTemplateArgs()[1];
66  if (DeleterArgument.getKind() != TemplateArgument::Type)
67  return nullptr;
68  return DeleterArgument.getAsType().getTypePtr();
69 }
70 
71 bool areDeletersCompatible(const MatchFinder::MatchResult &Result) {
72  const Type *LeftDeleterType = getDeleterForUniquePtr(Result, "left_class");
73  const Type *RightDeleterType = getDeleterForUniquePtr(Result, "right_class");
74 
75  if (LeftDeleterType->getUnqualifiedDesugaredType() ==
76  RightDeleterType->getUnqualifiedDesugaredType()) {
77  // Same type. We assume they are compatible.
78  // This check handles the case where the deleters are function pointers.
79  return true;
80  }
81 
82  const CXXRecordDecl *LeftDeleter = LeftDeleterType->getAsCXXRecordDecl();
83  const CXXRecordDecl *RightDeleter = RightDeleterType->getAsCXXRecordDecl();
84  if (!LeftDeleter || !RightDeleter)
85  return false;
86 
87  if (LeftDeleter->getCanonicalDecl() == RightDeleter->getCanonicalDecl()) {
88  // Same class. We assume they are compatible.
89  return true;
90  }
91 
92  const auto *LeftAsTemplate =
93  dyn_cast<ClassTemplateSpecializationDecl>(LeftDeleter);
94  const auto *RightAsTemplate =
95  dyn_cast<ClassTemplateSpecializationDecl>(RightDeleter);
96  if (LeftAsTemplate && RightAsTemplate &&
97  LeftAsTemplate->getSpecializedTemplate() ==
98  RightAsTemplate->getSpecializedTemplate()) {
99  // They are different instantiations of the same template. We assume they
100  // are compatible.
101  // This handles things like std::default_delete<Base> vs.
102  // std::default_delete<Derived>.
103  return true;
104  }
105  return false;
106 }
107 
108 } // namespace
109 
110 void UniqueptrResetReleaseCheck::check(const MatchFinder::MatchResult &Result) {
111  if (!areDeletersCompatible(Result))
112  return;
113 
114  const auto *ResetMember = Result.Nodes.getNodeAs<MemberExpr>("reset_member");
115  const auto *ReleaseMember =
116  Result.Nodes.getNodeAs<MemberExpr>("release_member");
117  const auto *Right = Result.Nodes.getNodeAs<Expr>("right");
118  const auto *ResetCall =
119  Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset_call");
120 
121  StringRef AssignmentText = " = ";
122  StringRef TrailingText = "";
123  bool NeedsUtilityInclude = false;
124  if (ReleaseMember->isArrow()) {
125  AssignmentText = " = std::move(*";
126  TrailingText = ")";
127  NeedsUtilityInclude = true;
128  } else if (!Right->isPRValue()) {
129  AssignmentText = " = std::move(";
130  TrailingText = ")";
131  NeedsUtilityInclude = true;
132  }
133 
134  auto D = diag(ResetMember->getExprLoc(),
135  "prefer 'unique_ptr<>' assignment over 'release' and 'reset'");
136  if (ResetMember->isArrow())
137  D << FixItHint::CreateInsertion(ResetMember->getBeginLoc(), "*");
138  D << FixItHint::CreateReplacement(
139  CharSourceRange::getCharRange(ResetMember->getOperatorLoc(),
140  Right->getBeginLoc()),
141  AssignmentText)
142  << FixItHint::CreateReplacement(
143  CharSourceRange::getTokenRange(ReleaseMember->getOperatorLoc(),
144  ResetCall->getEndLoc()),
145  TrailingText);
146  if (NeedsUtilityInclude)
147  D << Inserter.createIncludeInsertion(
148  Result.SourceManager->getFileID(ResetMember->getBeginLoc()),
149  "<utility>");
150 }
151 } // namespace misc
152 } // namespace tidy
153 } // namespace clang
clang::tidy::ClangTidyOptions::OptionMap
llvm::StringMap< ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:115
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::tidy::misc::UniqueptrResetReleaseCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: UniqueptrResetReleaseCheck.cpp:26
clang::tidy::utils::IncludeInserter::registerPreprocessor
void registerPreprocessor(Preprocessor *PP)
Registers this with the Preprocessor PP, must be called before this class is used.
Definition: IncludeInserter.cpp:43
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:53
clang::ast_matchers
Definition: AbseilMatcher.h:14
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:415
clang::tidy::misc::UniqueptrResetReleaseCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: UniqueptrResetReleaseCheck.cpp:110
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:66
clang::tidy::misc::UniqueptrResetReleaseCheck::registerPPCallbacks
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
Definition: UniqueptrResetReleaseCheck.cpp:31
UniqueptrResetReleaseCheck.h
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidyCheck.cpp:25
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:29
clang::tidy::utils::IncludeInserter::getStyle
IncludeSorter::IncludeStyle getStyle() const
Definition: IncludeInserter.h:85
ID
static char ID
Definition: Logger.cpp:74
clang::tidy::misc::UniqueptrResetReleaseCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: UniqueptrResetReleaseCheck.cpp:36
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::utils::IncludeInserter::createIncludeInsertion
llvm::Optional< FixItHint > createIncludeInsertion(FileID FileID, llvm::StringRef Header)
Creates a Header inclusion directive fixit in the File FileID.
Definition: IncludeInserter.cpp:71
clang::tidy::ClangTidyCheck::OptionsView::store
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidyCheck.cpp:120