[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clang-tidy / cppcoreguidelines / RvalueReferenceParamNotMovedCheck.cpp
blobda49d5610e229ed2798d74d40aecb709827a346c
1 //===--- RvalueReferenceParamNotMovedCheck.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 //===----------------------------------------------------------------------===//
9 #include "RvalueReferenceParamNotMovedCheck.h"
10 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers;
16 namespace clang::tidy::cppcoreguidelines {
18 using matchers::hasUnevaluatedContext;
20 namespace {
21 AST_MATCHER_P(LambdaExpr, valueCapturesVar, DeclarationMatcher, VarMatcher) {
22 return std::find_if(Node.capture_begin(), Node.capture_end(),
23 [&](const LambdaCapture &Capture) {
24 return Capture.capturesVariable() &&
25 VarMatcher.matches(*Capture.getCapturedVar(),
26 Finder, Builder) &&
27 Capture.getCaptureKind() == LCK_ByCopy;
28 }) != Node.capture_end();
30 AST_MATCHER_P2(Stmt, argumentOf, bool, AllowPartialMove, StatementMatcher,
31 Ref) {
32 if (AllowPartialMove) {
33 return stmt(anyOf(Ref, hasDescendant(Ref))).matches(Node, Finder, Builder);
34 } else {
35 return Ref.matches(Node, Finder, Builder);
38 } // namespace
40 void RvalueReferenceParamNotMovedCheck::registerMatchers(MatchFinder *Finder) {
41 auto ToParam = hasAnyParameter(parmVarDecl(equalsBoundNode("param")));
43 StatementMatcher MoveCallMatcher =
44 callExpr(
45 argumentCountIs(1),
46 anyOf(callee(functionDecl(hasName("::std::move"))),
47 callee(unresolvedLookupExpr(hasAnyDeclaration(
48 namedDecl(hasUnderlyingDecl(hasName("::std::move"))))))),
49 hasArgument(
50 0, argumentOf(
51 AllowPartialMove,
52 declRefExpr(to(equalsBoundNode("param"))).bind("ref"))),
53 unless(hasAncestor(
54 lambdaExpr(valueCapturesVar(equalsBoundNode("param"))))),
55 unless(anyOf(hasAncestor(typeLoc()),
56 hasAncestor(expr(hasUnevaluatedContext())))))
57 .bind("move-call");
59 Finder->addMatcher(
60 parmVarDecl(
61 hasType(type(rValueReferenceType())), parmVarDecl().bind("param"),
62 unless(hasType(references(qualType(
63 anyOf(isConstQualified(), substTemplateTypeParmType()))))),
64 optionally(hasType(qualType(references(templateTypeParmType(
65 hasDeclaration(templateTypeParmDecl().bind("template-type"))))))),
66 anyOf(hasAncestor(cxxConstructorDecl(
67 ToParam, isDefinition(), unless(isMoveConstructor()),
68 optionally(hasDescendant(MoveCallMatcher)))),
69 hasAncestor(functionDecl(
70 unless(cxxConstructorDecl()), ToParam,
71 unless(cxxMethodDecl(isMoveAssignmentOperator())),
72 hasBody(optionally(hasDescendant(MoveCallMatcher))))))),
73 this);
76 void RvalueReferenceParamNotMovedCheck::check(
77 const MatchFinder::MatchResult &Result) {
78 const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
79 const auto *TemplateType =
80 Result.Nodes.getNodeAs<TemplateTypeParmDecl>("template-type");
82 if (!Param)
83 return;
85 if (IgnoreUnnamedParams && Param->getName().empty())
86 return;
88 const auto *Function = dyn_cast<FunctionDecl>(Param->getDeclContext());
89 if (!Function)
90 return;
92 if (IgnoreNonDeducedTemplateTypes && TemplateType)
93 return;
95 if (TemplateType) {
96 if (const FunctionTemplateDecl *FuncTemplate =
97 Function->getDescribedFunctionTemplate()) {
98 const TemplateParameterList *Params =
99 FuncTemplate->getTemplateParameters();
100 if (llvm::is_contained(*Params, TemplateType)) {
101 // Ignore forwarding reference
102 return;
107 const auto *MoveCall = Result.Nodes.getNodeAs<CallExpr>("move-call");
108 if (!MoveCall) {
109 diag(Param->getLocation(),
110 "rvalue reference parameter %0 is never moved from "
111 "inside the function body")
112 << Param;
116 RvalueReferenceParamNotMovedCheck::RvalueReferenceParamNotMovedCheck(
117 StringRef Name, ClangTidyContext *Context)
118 : ClangTidyCheck(Name, Context),
119 AllowPartialMove(Options.getLocalOrGlobal("AllowPartialMove", false)),
120 IgnoreUnnamedParams(
121 Options.getLocalOrGlobal("IgnoreUnnamedParams", false)),
122 IgnoreNonDeducedTemplateTypes(
123 Options.getLocalOrGlobal("IgnoreNonDeducedTemplateTypes", false)) {}
125 void RvalueReferenceParamNotMovedCheck::storeOptions(
126 ClangTidyOptions::OptionMap &Opts) {
127 Options.store(Opts, "AllowPartialMove", AllowPartialMove);
128 Options.store(Opts, "IgnoreUnnamedParams", IgnoreUnnamedParams);
129 Options.store(Opts, "IgnoreNonDeducedTemplateTypes",
130 IgnoreNonDeducedTemplateTypes);
133 } // namespace clang::tidy::cppcoreguidelines