1//===--- NoAutomaticMoveCheck.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 "NoAutomaticMoveCheck.h"
10#include "../utils/Matchers.h"
11#include "../utils/OptionsUtils.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang::tidy::performance {
18
19namespace {
20
21AST_MATCHER(VarDecl, isNRVOVariable) { return Node.isNRVOVariable(); }
22
23} // namespace
24
25NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name,
26 ClangTidyContext *Context)
27 : ClangTidyCheck(Name, Context),
28 AllowedTypes(
29 utils::options::parseStringList(Option: Options.get(LocalName: "AllowedTypes", Default: ""))) {}
30
31void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) {
32 const auto NonNrvoConstLocalVariable =
33 varDecl(hasLocalStorage(), unless(hasType(InnerMatcher: lValueReferenceType())),
34 unless(isNRVOVariable()),
35 hasType(InnerMatcher: qualType(
36 isConstQualified(),
37 hasCanonicalType(InnerMatcher: matchers::isExpensiveToCopy()),
38 unless(hasDeclaration(InnerMatcher: namedDecl(
39 matchers::matchesAnyListedName(NameList: AllowedTypes)))))))
40 .bind(ID: "vardecl");
41
42 // A matcher for a `DstT::DstT(const Src&)` where DstT also has a
43 // `DstT::DstT(Src&&)`.
44 const auto LValueRefCtor = cxxConstructorDecl(
45 hasParameter(N: 0,
46 InnerMatcher: hasType(InnerMatcher: lValueReferenceType(pointee(type().bind(ID: "SrcT"))))),
47 ofClass(InnerMatcher: cxxRecordDecl(hasMethod(InnerMatcher: cxxConstructorDecl(
48 hasParameter(N: 0, InnerMatcher: hasType(InnerMatcher: rValueReferenceType(
49 pointee(type(equalsBoundNode(ID: "SrcT")))))))))));
50
51 // A matcher for `DstT::DstT(const Src&&)`, which typically comes from an
52 // instantiation of `template <typename U> DstT::DstT(U&&)`.
53 const auto ConstRefRefCtor = cxxConstructorDecl(
54 parameterCountIs(N: 1),
55 hasParameter(N: 0,
56 InnerMatcher: hasType(InnerMatcher: rValueReferenceType(pointee(isConstQualified())))));
57
58 Finder->addMatcher(
59 NodeMatch: traverse(
60 TK: TK_AsIs,
61 InnerMatcher: returnStmt(hasReturnValue(
62 InnerMatcher: ignoringElidableConstructorCall(InnerMatcher: ignoringParenImpCasts(
63 InnerMatcher: cxxConstructExpr(
64 hasDeclaration(InnerMatcher: anyOf(LValueRefCtor, ConstRefRefCtor)),
65 hasArgument(N: 0, InnerMatcher: ignoringParenImpCasts(InnerMatcher: declRefExpr(
66 to(InnerMatcher: NonNrvoConstLocalVariable)))))
67 .bind(ID: "ctor_call")))))),
68 Action: this);
69}
70
71void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult &Result) {
72 const auto *Var = Result.Nodes.getNodeAs<VarDecl>(ID: "vardecl");
73 const auto *CtorCall = Result.Nodes.getNodeAs<Expr>(ID: "ctor_call");
74 diag(Loc: CtorCall->getExprLoc(), Description: "constness of '%0' prevents automatic move")
75 << Var->getName();
76}
77
78void NoAutomaticMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
79 Options.store(Options&: Opts, LocalName: "AllowedTypes",
80 Value: utils::options::serializeStringList(Strings: AllowedTypes));
81}
82
83} // namespace clang::tidy::performance
84

source code of clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp