clang-tools 24.0.0git
NoAutomaticMoveCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include "../utils/Matchers.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14
15using namespace clang::ast_matchers;
16
18
19namespace {
20
21AST_MATCHER(VarDecl, isNRVOVariable) { return Node.isNRVOVariable(); }
22
23AST_MATCHER(DeclRefExpr, refersToEnclosingVariableOrCapture) {
24 return Node.refersToEnclosingVariableOrCapture();
25}
26
27} // namespace
28
30 ClangTidyContext *Context)
31 : ClangTidyCheck(Name, Context),
32 AllowedTypes(
33 utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
34
35void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) {
36 const auto NonNrvoConstLocalVariable =
37 varDecl(hasLocalStorage(), unless(hasType(lValueReferenceType())),
38 unless(isNRVOVariable()),
39 hasType(qualType(
40 isConstQualified(),
41 hasCanonicalType(matchers::isExpensiveToCopy()),
42 unless(hasDeclaration(namedDecl(
43 matchers::matchesAnyListedRegexName(AllowedTypes)))))))
44 .bind("vardecl");
45
46 // A matcher for a `DstT::DstT(const Src&)` where DstT also has a
47 // `DstT::DstT(Src&&)`.
48 const auto LValueRefCtor = cxxConstructorDecl(
49 hasParameter(0, hasType(hasCanonicalType(
50 lValueReferenceType(pointee(type().bind("SrcT")))))),
51 ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl(
52 hasParameter(0, hasType(hasCanonicalType(rValueReferenceType(
53 pointee(type(equalsBoundNode("SrcT"))))))))))));
54
55 // A matcher for `DstT::DstT(const Src&&)`, which typically comes from an
56 // instantiation of `template <typename U> DstT::DstT(U&&)`.
57 const auto ConstRefRefCtor = cxxConstructorDecl(
58 parameterCountIs(1),
59 hasParameter(0,
60 hasType(rValueReferenceType(pointee(isConstQualified())))));
61
62 Finder->addMatcher(
63 traverse(
64 TK_AsIs,
65 returnStmt(hasReturnValue(
66 ignoringElidableConstructorCall(ignoringParenImpCasts(
67 cxxConstructExpr(
68 hasDeclaration(anyOf(LValueRefCtor, ConstRefRefCtor)),
69 hasArgument(
70 0,
71 ignoringParenImpCasts(declRefExpr(
72 to(NonNrvoConstLocalVariable),
73 unless(refersToEnclosingVariableOrCapture())))))
74 .bind("ctor_call")))))),
75 this);
76}
77
78void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult &Result) {
79 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("vardecl");
80 const auto *CtorCall = Result.Nodes.getNodeAs<Expr>("ctor_call");
81 diag(CtorCall->getExprLoc(), "constness of '%0' prevents automatic move")
82 << Var->getName();
83}
84
86 Options.store(Opts, "AllowedTypes",
88}
89
90} // namespace clang::tidy::performance
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
NoAutomaticMoveCheck(StringRef Name, ClangTidyContext *Context)
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedRegexName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap