summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/misc/UniqueptrResetRelease.cpp
blob: 3f3a68c1ecb04e55dbf30e2433d06bcc6594de17 (plain)
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
OpenPOWER on IntegriCloud