1 //===--- MissingStdForwardCheck.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 "MissingStdForwardCheck.h"
10 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/ExprConcepts.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 using namespace clang::ast_matchers
;
17 namespace clang::tidy::cppcoreguidelines
{
21 using matchers::hasUnevaluatedContext
;
23 AST_MATCHER_P(QualType
, possiblyPackExpansionOf
,
24 ast_matchers::internal::Matcher
<QualType
>, InnerMatcher
) {
25 return InnerMatcher
.matches(Node
.getNonPackExpansionType(), Finder
, Builder
);
28 AST_MATCHER(ParmVarDecl
, isTemplateTypeParameter
) {
29 ast_matchers::internal::Matcher
<QualType
> Inner
= possiblyPackExpansionOf(
30 qualType(rValueReferenceType(),
31 references(templateTypeParmType(
32 hasDeclaration(templateTypeParmDecl()))),
33 unless(references(qualType(isConstQualified())))));
34 if (!Inner
.matches(Node
.getType(), Finder
, Builder
))
37 const auto *Function
= dyn_cast
<FunctionDecl
>(Node
.getDeclContext());
41 const FunctionTemplateDecl
*FuncTemplate
=
42 Function
->getDescribedFunctionTemplate();
47 Node
.getType().getNonPackExpansionType()->getPointeeType();
48 const auto *TemplateType
= ParamType
->getAs
<TemplateTypeParmType
>();
52 return TemplateType
->getDepth() ==
53 FuncTemplate
->getTemplateParameters()->getDepth();
58 void MissingStdForwardCheck::registerMatchers(MatchFinder
*Finder
) {
59 auto ToParam
= hasAnyParameter(parmVarDecl(equalsBoundNode("param")));
61 auto ForwardCallMatcher
= callExpr(
62 forCallable(equalsBoundNode("func")), argumentCountIs(1),
63 callee(unresolvedLookupExpr(hasAnyDeclaration(
64 namedDecl(hasUnderlyingDecl(hasName("::std::forward")))))),
65 hasArgument(0, declRefExpr(to(equalsBoundNode("param"))).bind("ref")),
66 unless(anyOf(hasAncestor(typeLoc()),
67 hasAncestor(expr(hasUnevaluatedContext())))));
70 parmVarDecl(parmVarDecl().bind("param"), isTemplateTypeParameter(),
71 hasAncestor(functionDecl().bind("func")),
72 hasAncestor(functionDecl(
73 isDefinition(), equalsBoundNode("func"), ToParam
,
74 unless(hasDescendant(std::move(ForwardCallMatcher
)))))),
78 void MissingStdForwardCheck::check(const MatchFinder::MatchResult
&Result
) {
79 const auto *Param
= Result
.Nodes
.getNodeAs
<ParmVarDecl
>("param");
84 diag(Param
->getLocation(),
85 "forwarding reference parameter %0 is never forwarded "
86 "inside the function body")
90 } // namespace clang::tidy::cppcoreguidelines