clang-tools 22.0.0git
AmbiguousSmartptrResetCallCheck.cpp
Go to the documentation of this file.
1//===--- AmbiguousSmartptrResetCallCheck.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
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/ASTMatchers/ASTMatchers.h"
14#include "clang/Lex/Lexer.h"
15
16using namespace clang::ast_matchers;
17
19
20namespace {
21
22AST_MATCHER(CXXMethodDecl, hasOnlyDefaultParameters) {
23 for (const auto *Param : Node.parameters()) {
24 if (!Param->hasDefaultArg())
25 return false;
26 }
27
28 return true;
29}
30
31const auto DefaultSmartPointers = "::std::shared_ptr;::std::unique_ptr;"
32 "::boost::shared_ptr";
33} // namespace
34
36 StringRef Name, ClangTidyContext *Context)
37 : ClangTidyCheck(Name, Context),
38 SmartPointers(utils::options::parseStringList(
39 Options.get("SmartPointers", DefaultSmartPointers))) {}
40
43 Options.store(Opts, "SmartPointers",
45}
46
48 const auto IsSmartptr = hasAnyName(SmartPointers);
49
50 const auto ResetMethod =
51 cxxMethodDecl(hasName("reset"), hasOnlyDefaultParameters());
52
53 const auto TypeWithReset =
54 anyOf(cxxRecordDecl(
55 anyOf(hasMethod(ResetMethod),
56 isDerivedFrom(cxxRecordDecl(hasMethod(ResetMethod))))),
57 classTemplateSpecializationDecl(
58 hasSpecializedTemplate(classTemplateDecl(has(ResetMethod)))));
59
60 const auto SmartptrWithReset = expr(hasType(hasUnqualifiedDesugaredType(
61 recordType(hasDeclaration(classTemplateSpecializationDecl(
62 IsSmartptr,
63 hasTemplateArgument(
64 0, templateArgument(refersToType(hasUnqualifiedDesugaredType(
65 recordType(hasDeclaration(TypeWithReset))))))))))));
66
67 Finder->addMatcher(
68 cxxMemberCallExpr(
69 callee(ResetMethod),
70 unless(hasAnyArgument(expr(unless(cxxDefaultArgExpr())))),
71 anyOf(on(cxxOperatorCallExpr(hasOverloadedOperatorName("->"),
72 hasArgument(0, SmartptrWithReset))
73 .bind("ArrowOp")),
74 on(SmartptrWithReset)))
75 .bind("MemberCall"),
76 this);
77}
78
80 const MatchFinder::MatchResult &Result) {
81 const auto *MemberCall =
82 Result.Nodes.getNodeAs<CXXMemberCallExpr>("MemberCall");
83 assert(MemberCall);
84
85 if (const auto *Arrow =
86 Result.Nodes.getNodeAs<CXXOperatorCallExpr>("ArrowOp")) {
87 const CharSourceRange SmartptrSourceRange =
88 Lexer::getAsCharRange(Arrow->getArg(0)->getSourceRange(),
89 *Result.SourceManager, getLangOpts());
90
91 diag(MemberCall->getBeginLoc(),
92 "ambiguous call to 'reset()' on a pointee of a smart pointer, prefer "
93 "more explicit approach");
94
95 diag(MemberCall->getBeginLoc(),
96 "consider dereferencing smart pointer to call 'reset' method "
97 "of the pointee here",
98 DiagnosticIDs::Note)
99 << FixItHint::CreateInsertion(SmartptrSourceRange.getBegin(), "(*")
100 << FixItHint::CreateInsertion(SmartptrSourceRange.getEnd(), ")")
101 << FixItHint::CreateReplacement(
102 CharSourceRange::getCharRange(
103 Arrow->getOperatorLoc(),
104 Arrow->getOperatorLoc().getLocWithOffset(2)),
105 ".");
106 } else {
107 const auto *Member = cast<MemberExpr>(MemberCall->getCallee());
108 assert(Member);
109
110 diag(MemberCall->getBeginLoc(),
111 "ambiguous call to 'reset()' on a smart pointer with pointee that "
112 "also has a 'reset()' method, prefer more explicit approach");
113
114 diag(MemberCall->getBeginLoc(),
115 "consider assigning the pointer to 'nullptr' here",
116 DiagnosticIDs::Note)
117 << FixItHint::CreateReplacement(
118 SourceRange(Member->getOperatorLoc(), Member->getOperatorLoc()),
119 " =")
120 << FixItHint::CreateReplacement(
121 SourceRange(Member->getMemberLoc(), MemberCall->getEndLoc()),
122 " nullptr");
123 }
124}
125
126} // namespace clang::tidy::readability
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap