10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "clang/Lex/Lexer.h"
20 Inserter(Options.getLocalOrGlobal(
"IncludeStyle",
21 utils::IncludeSorter::IS_LLVM),
22 areDiagsSelfContained()) {}
30 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
40 ofClass(cxxRecordDecl(hasName(
"::std::unique_ptr"),
41 decl().bind(
"left_class"))))))
42 .bind(
"reset_member")),
44 0, ignoringParenImpCasts(cxxMemberCallExpr(
45 on(expr().bind(
"right")),
46 callee(memberExpr(member(cxxMethodDecl(
48 ofClass(cxxRecordDecl(
49 hasName(
"::std::unique_ptr"),
50 decl().bind(
"right_class"))))))
51 .bind(
"release_member"))))))
57const Type *getDeleterForUniquePtr(
const MatchFinder::MatchResult &Result,
60 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
ID);
63 auto DeleterArgument = Class->getTemplateArgs()[1];
64 if (DeleterArgument.getKind() != TemplateArgument::Type)
66 return DeleterArgument.getAsType().getTypePtr();
69bool areDeletersCompatible(
const MatchFinder::MatchResult &Result) {
70 const Type *LeftDeleterType = getDeleterForUniquePtr(Result,
"left_class");
71 const Type *RightDeleterType = getDeleterForUniquePtr(Result,
"right_class");
73 if (LeftDeleterType->getUnqualifiedDesugaredType() ==
74 RightDeleterType->getUnqualifiedDesugaredType()) {
80 const CXXRecordDecl *LeftDeleter = LeftDeleterType->getAsCXXRecordDecl();
81 const CXXRecordDecl *RightDeleter = RightDeleterType->getAsCXXRecordDecl();
82 if (!LeftDeleter || !RightDeleter)
85 if (LeftDeleter->getCanonicalDecl() == RightDeleter->getCanonicalDecl()) {
90 const auto *LeftAsTemplate =
91 dyn_cast<ClassTemplateSpecializationDecl>(LeftDeleter);
92 const auto *RightAsTemplate =
93 dyn_cast<ClassTemplateSpecializationDecl>(RightDeleter);
94 if (LeftAsTemplate && RightAsTemplate &&
95 LeftAsTemplate->getSpecializedTemplate() ==
96 RightAsTemplate->getSpecializedTemplate()) {
109 if (!areDeletersCompatible(Result))
112 const auto *ResetMember = Result.Nodes.getNodeAs<MemberExpr>(
"reset_member");
113 const auto *ReleaseMember =
114 Result.Nodes.getNodeAs<MemberExpr>(
"release_member");
115 const auto *Right = Result.Nodes.getNodeAs<Expr>(
"right");
116 const auto *ResetCall =
117 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"reset_call");
119 StringRef AssignmentText =
" = ";
120 StringRef TrailingText =
"";
121 bool NeedsUtilityInclude =
false;
122 if (ReleaseMember->isArrow()) {
123 AssignmentText =
" = std::move(*";
125 NeedsUtilityInclude =
true;
126 }
else if (!Right->isPRValue()) {
127 AssignmentText =
" = std::move(";
129 NeedsUtilityInclude =
true;
132 auto D =
diag(ResetMember->getExprLoc(),
133 "prefer 'unique_ptr<>' assignment over 'release' and 'reset'");
134 if (ResetMember->isArrow())
135 D << FixItHint::CreateInsertion(ResetMember->getBeginLoc(),
"*");
136 D << FixItHint::CreateReplacement(
137 CharSourceRange::getCharRange(ResetMember->getOperatorLoc(),
138 Right->getBeginLoc()),
140 << FixItHint::CreateReplacement(
141 CharSourceRange::getTokenRange(ReleaseMember->getOperatorLoc(),
142 ResetCall->getEndLoc()),
144 if (NeedsUtilityInclude)
146 Result.SourceManager->getFileID(ResetMember->getBeginLoc()),
llvm::SmallString< 256U > Name
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.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
UniqueptrResetReleaseCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerPreprocessor(Preprocessor *PP)
Registers this with the Preprocessor PP, must be called before this class is used.
std::optional< FixItHint > createIncludeInsertion(FileID FileID, llvm::StringRef Header)
Creates a Header inclusion directive fixit in the File FileID.
IncludeSorter::IncludeStyle getStyle() const
llvm::StringMap< ClangTidyValue > OptionMap