10 #include "clang/ASTMatchers/ASTMatchFinder.h" 11 #include "clang/Lex/Lexer.h" 19 void UniqueptrResetReleaseCheck::registerMatchers(MatchFinder *Finder) {
22 if (!getLangOpts().CPlusPlus11)
27 on(expr().bind(
"left")), callee(memberExpr().bind(
"reset_member")),
29 cxxMethodDecl(hasName(
"reset"),
30 ofClass(cxxRecordDecl(hasName(
"::std::unique_ptr"),
31 decl().bind(
"left_class"))))),
32 has(ignoringParenImpCasts(cxxMemberCallExpr(
33 on(expr().bind(
"right")),
34 callee(memberExpr().bind(
"release_member")),
37 ofClass(cxxRecordDecl(hasName(
"::std::unique_ptr"),
38 decl().bind(
"right_class")))))))))
44 const Type *getDeleterForUniquePtr(
const MatchFinder::MatchResult &Result,
47 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(ID);
50 auto DeleterArgument = Class->getTemplateArgs()[1];
53 return DeleterArgument.getAsType().getTypePtr();
56 bool areDeletersCompatible(
const MatchFinder::MatchResult &Result) {
57 const Type *LeftDeleterType = getDeleterForUniquePtr(Result,
"left_class");
58 const Type *RightDeleterType = getDeleterForUniquePtr(Result,
"right_class");
60 if (LeftDeleterType->getUnqualifiedDesugaredType() ==
61 RightDeleterType->getUnqualifiedDesugaredType()) {
67 const CXXRecordDecl *LeftDeleter = LeftDeleterType->getAsCXXRecordDecl();
68 const CXXRecordDecl *RightDeleter = RightDeleterType->getAsCXXRecordDecl();
69 if (!LeftDeleter || !RightDeleter)
72 if (LeftDeleter->getCanonicalDecl() == RightDeleter->getCanonicalDecl()) {
77 const auto *LeftAsTemplate =
78 dyn_cast<ClassTemplateSpecializationDecl>(LeftDeleter);
79 const auto *RightAsTemplate =
80 dyn_cast<ClassTemplateSpecializationDecl>(RightDeleter);
81 if (LeftAsTemplate && RightAsTemplate &&
82 LeftAsTemplate->getSpecializedTemplate() ==
83 RightAsTemplate->getSpecializedTemplate()) {
95 void UniqueptrResetReleaseCheck::check(
const MatchFinder::MatchResult &Result) {
96 if (!areDeletersCompatible(Result))
99 const auto *ResetMember = Result.Nodes.getNodeAs<MemberExpr>(
"reset_member");
100 const auto *ReleaseMember =
101 Result.Nodes.getNodeAs<MemberExpr>(
"release_member");
102 const auto *Right = Result.Nodes.getNodeAs<Expr>(
"right");
103 const auto *Left = Result.Nodes.getNodeAs<Expr>(
"left");
104 const auto *ResetCall =
105 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"reset_call");
107 std::string LeftText = clang::Lexer::getSourceText(
109 *Result.SourceManager, getLangOpts());
110 std::string RightText = clang::Lexer::getSourceText(
112 *Result.SourceManager, getLangOpts());
114 if (ResetMember->isArrow())
115 LeftText =
"*" + LeftText;
116 if (ReleaseMember->isArrow())
117 RightText =
"*" + RightText;
118 std::string DiagText;
120 if (!Right->isRValue() || ReleaseMember->isArrow()) {
121 RightText =
"std::move(" + RightText +
")";
122 DiagText =
"prefer ptr1 = std::move(ptr2) over ptr1.reset(ptr2.release())";
125 "prefer ptr = ReturnUnique() over ptr.reset(ReturnUnique().release())";
127 std::string NewText = LeftText +
" = " + RightText;
129 diag(ResetMember->getExprLoc(), DiagText) << FixItHint::CreateReplacement(
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//