1 //===--- NoAutomaticMoveCheck.cpp - clang-tidy ----------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
15 using namespace clang::ast_matchers
;
17 namespace clang::tidy::performance
{
21 AST_MATCHER(VarDecl
, isNRVOVariable
) { return Node
.isNRVOVariable(); }
25 NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name
,
26 ClangTidyContext
*Context
)
27 : ClangTidyCheck(Name
, Context
),
29 utils::options::parseStringList(Options
.get("AllowedTypes", ""))) {}
31 void NoAutomaticMoveCheck::registerMatchers(MatchFinder
*Finder
) {
32 const auto NonNrvoConstLocalVariable
=
33 varDecl(hasLocalStorage(), unless(hasType(lValueReferenceType())),
34 unless(isNRVOVariable()),
37 hasCanonicalType(matchers::isExpensiveToCopy()),
38 unless(hasDeclaration(namedDecl(
39 matchers::matchesAnyListedName(AllowedTypes
)))))))
42 // A matcher for a `DstT::DstT(const Src&)` where DstT also has a
43 // `DstT::DstT(Src&&)`.
44 const auto LValueRefCtor
= cxxConstructorDecl(
46 hasType(lValueReferenceType(pointee(type().bind("SrcT"))))),
47 ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl(
48 hasParameter(0, hasType(rValueReferenceType(
49 pointee(type(equalsBoundNode("SrcT")))))))))));
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(
56 hasType(rValueReferenceType(pointee(isConstQualified())))));
61 returnStmt(hasReturnValue(
62 ignoringElidableConstructorCall(ignoringParenImpCasts(
64 hasDeclaration(anyOf(LValueRefCtor
, ConstRefRefCtor
)),
65 hasArgument(0, ignoringParenImpCasts(declRefExpr(
66 to(NonNrvoConstLocalVariable
)))))
67 .bind("ctor_call")))))),
71 void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult
&Result
) {
72 const auto *Var
= Result
.Nodes
.getNodeAs
<VarDecl
>("vardecl");
73 const auto *CtorCall
= Result
.Nodes
.getNodeAs
<Expr
>("ctor_call");
74 diag(CtorCall
->getExprLoc(), "constness of '%0' prevents automatic move")
78 void NoAutomaticMoveCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
79 Options
.store(Opts
, "AllowedTypes",
80 utils::options::serializeStringList(AllowedTypes
));
83 } // namespace clang::tidy::performance