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
9#include "AmbiguousSmartptrResetCallCheck.h"
10#include "../utils/OptionsUtils.h"
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
18namespace clang::tidy::readability {
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
35AmbiguousSmartptrResetCallCheck::AmbiguousSmartptrResetCallCheck(
36 StringRef Name, ClangTidyContext *Context)
37 : ClangTidyCheck(Name, Context),
38 SmartPointers(utils::options::parseStringList(
39 Option: Options.get(LocalName: "SmartPointers", Default: DefaultSmartPointers))) {}
40
41void AmbiguousSmartptrResetCallCheck::storeOptions(
42 ClangTidyOptions::OptionMap &Opts) {
43 Options.store(Options&: Opts, LocalName: "SmartPointers",
44 Value: utils::options::serializeStringList(Strings: SmartPointers));
45}
46
47void AmbiguousSmartptrResetCallCheck::registerMatchers(MatchFinder *Finder) {
48 const auto IsSmartptr = hasAnyName(SmartPointers);
49
50 const auto ResetMethod =
51 cxxMethodDecl(hasName(Name: "reset"), hasOnlyDefaultParameters());
52
53 const auto TypeWithReset =
54 anyOf(cxxRecordDecl(
55 anyOf(hasMethod(InnerMatcher: ResetMethod),
56 isDerivedFrom(Base: cxxRecordDecl(hasMethod(InnerMatcher: ResetMethod))))),
57 classTemplateSpecializationDecl(
58 hasSpecializedTemplate(InnerMatcher: classTemplateDecl(has(ResetMethod)))));
59
60 const auto SmartptrWithReset = expr(hasType(InnerMatcher: hasUnqualifiedDesugaredType(
61 InnerMatcher: recordType(hasDeclaration(InnerMatcher: classTemplateSpecializationDecl(
62 IsSmartptr,
63 hasTemplateArgument(
64 N: 0, InnerMatcher: templateArgument(refersToType(InnerMatcher: hasUnqualifiedDesugaredType(
65 InnerMatcher: recordType(hasDeclaration(InnerMatcher: TypeWithReset))))))))))));
66
67 Finder->addMatcher(
68 NodeMatch: cxxMemberCallExpr(
69 callee(InnerMatcher: ResetMethod),
70 unless(hasAnyArgument(InnerMatcher: expr(unless(cxxDefaultArgExpr())))),
71 anyOf(on(InnerMatcher: cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "->"),
72 hasArgument(N: 0, InnerMatcher: SmartptrWithReset))
73 .bind(ID: "ArrowOp")),
74 on(InnerMatcher: SmartptrWithReset)))
75 .bind(ID: "MemberCall"),
76 Action: this);
77}
78
79void AmbiguousSmartptrResetCallCheck::check(
80 const MatchFinder::MatchResult &Result) {
81 const auto *MemberCall =
82 Result.Nodes.getNodeAs<CXXMemberCallExpr>(ID: "MemberCall");
83 assert(MemberCall);
84
85 if (const auto *Arrow =
86 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(ID: "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(InsertionLoc: SmartptrSourceRange.getBegin(), Code: "(*")
100 << FixItHint::CreateInsertion(InsertionLoc: SmartptrSourceRange.getEnd(), Code: ")")
101 << FixItHint::CreateReplacement(
102 RemoveRange: CharSourceRange::getCharRange(
103 B: Arrow->getOperatorLoc(),
104 E: Arrow->getOperatorLoc().getLocWithOffset(Offset: 2)),
105 Code: ".");
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 RemoveRange: SourceRange(Member->getOperatorLoc(), Member->getOperatorLoc()),
119 Code: " =")
120 << FixItHint::CreateReplacement(
121 RemoveRange: SourceRange(Member->getMemberLoc(), MemberCall->getEndLoc()),
122 Code: " nullptr");
123 }
124}
125
126} // namespace clang::tidy::readability
127

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp