1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
//===--- UniqueptrResetRelease.cpp - clang-tidy ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "UniqueptrResetRelease.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace misc {
void UniqueptrResetRelease::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
memberCallExpr(
on(expr().bind("left")), callee(memberExpr().bind("reset_member")),
callee(methodDecl(hasName("reset"),
ofClass(hasName("::std::unique_ptr")))),
has(memberCallExpr(
on(expr().bind("right")),
callee(memberExpr().bind("release_member")),
callee(methodDecl(hasName("release"),
ofClass(hasName("::std::unique_ptr")))))))
.bind("reset_call"),
this);
}
void UniqueptrResetRelease::check(const MatchFinder::MatchResult &Result) {
const auto *ResetMember = Result.Nodes.getNodeAs<MemberExpr>("reset_member");
const auto *ReleaseMember =
Result.Nodes.getNodeAs<MemberExpr>("release_member");
const auto *Right = Result.Nodes.getNodeAs<Expr>("right");
const auto *Left = Result.Nodes.getNodeAs<Expr>("left");
const auto *ResetCall =
Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset_call");
std::string LeftText = clang::Lexer::getSourceText(
CharSourceRange::getTokenRange(Left->getSourceRange()),
*Result.SourceManager, Result.Context->getLangOpts());
std::string RightText = clang::Lexer::getSourceText(
CharSourceRange::getTokenRange(Right->getSourceRange()),
*Result.SourceManager, Result.Context->getLangOpts());
if (ResetMember->isArrow())
LeftText = "*" + LeftText;
if (ReleaseMember->isArrow())
RightText = "*" + RightText;
std::string DiagText;
// Even if x was rvalue, *x is not rvalue anymore.
if (!Right->isRValue() || ReleaseMember->isArrow()) {
RightText = "std::move(" + RightText + ")";
DiagText = "prefer ptr1 = std::move(ptr2) over ptr1.reset(ptr2.release())";
} else {
DiagText =
"prefer ptr = ReturnUnique() over ptr.reset(ReturnUnique().release())";
}
std::string NewText = LeftText + " = " + RightText;
diag(ResetMember->getExprLoc(), DiagText)
<< FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(ResetCall->getSourceRange()), NewText);
}
} // namespace misc
} // namespace tidy
} // namespace clang
|