1 //===--- Matchers.h - 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 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
12 #include "TypeTraits.h"
13 #include "clang/AST/ExprConcepts.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
17 namespace clang::tidy::matchers
{
19 AST_MATCHER(BinaryOperator
, isRelationalOperator
) {
20 return Node
.isRelationalOp();
23 AST_MATCHER(BinaryOperator
, isEqualityOperator
) { return Node
.isEqualityOp(); }
25 AST_MATCHER(QualType
, isExpensiveToCopy
) {
26 std::optional
<bool> IsExpensive
=
27 utils::type_traits::isExpensiveToCopy(Node
, Finder
->getASTContext());
28 return IsExpensive
&& *IsExpensive
;
31 AST_MATCHER(RecordDecl
, isTriviallyDefaultConstructible
) {
32 return utils::type_traits::recordIsTriviallyDefaultConstructible(
33 Node
, Finder
->getASTContext());
36 AST_MATCHER(QualType
, isTriviallyDestructible
) {
37 return utils::type_traits::isTriviallyDestructible(Node
);
40 // Returns QualType matcher for references to const.
41 AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher
, isReferenceToConst
) {
42 using namespace ast_matchers
;
43 return referenceType(pointee(qualType(isConstQualified())));
46 // Returns QualType matcher for pointers to const.
47 AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher
, isPointerToConst
) {
48 using namespace ast_matchers
;
49 return pointerType(pointee(qualType(isConstQualified())));
52 // Returns QualType matcher for target char type only.
53 AST_MATCHER(QualType
, isSimpleChar
) {
54 const auto ActualType
= Node
.getTypePtr();
56 (ActualType
->isSpecificBuiltinType(BuiltinType::Char_S
) ||
57 ActualType
->isSpecificBuiltinType(BuiltinType::Char_U
));
60 AST_MATCHER(Expr
, hasUnevaluatedContext
) {
61 if (isa
<CXXNoexceptExpr
>(Node
) || isa
<RequiresExpr
>(Node
))
63 if (const auto *UnaryExpr
= dyn_cast
<UnaryExprOrTypeTraitExpr
>(&Node
)) {
64 switch (UnaryExpr
->getKind()) {
72 if (const auto *TypeIDExpr
= dyn_cast
<CXXTypeidExpr
>(&Node
))
73 return !TypeIDExpr
->isPotentiallyEvaluated();
77 // A matcher implementation that matches a list of type name regular expressions
78 // against a NamedDecl. If a regular expression contains the substring "::"
79 // matching will occur against the qualified name, otherwise only the typename.
80 class MatchesAnyListedNameMatcher
81 : public ast_matchers::internal::MatcherInterface
<NamedDecl
> {
83 explicit MatchesAnyListedNameMatcher(llvm::ArrayRef
<StringRef
> NameList
) {
85 NameList
.begin(), NameList
.end(), std::back_inserter(NameMatchers
),
86 [](const llvm::StringRef Name
) { return NameMatcher(Name
); });
91 enum class MatchMode
{
92 // Match against the unqualified name because the regular expression
93 // does not contain ":".
95 // Match against the qualified name because the regular expression
96 // contains ":" suggesting name and namespace should be matched.
98 // Match against the fully qualified name because the regular expression
105 NameMatcher(const llvm::StringRef Regex
)
106 : Regex(Regex
), Mode(determineMatchMode(Regex
)) {}
108 bool match(const NamedDecl
&ND
) const {
110 case MatchMode::MatchQualified
:
111 return Regex
.match(ND
.getQualifiedNameAsString());
112 case MatchMode::MatchFullyQualified
:
113 return Regex
.match("::" + ND
.getQualifiedNameAsString());
115 if (const IdentifierInfo
*II
= ND
.getIdentifier())
116 return Regex
.match(II
->getName());
122 MatchMode
determineMatchMode(llvm::StringRef Regex
) {
123 if (Regex
.starts_with(":") || Regex
.starts_with("^:")) {
124 return MatchMode::MatchFullyQualified
;
126 return Regex
.contains(":") ? MatchMode::MatchQualified
127 : MatchMode::MatchUnqualified
;
132 const NamedDecl
&Node
, ast_matchers::internal::ASTMatchFinder
*Finder
,
133 ast_matchers::internal::BoundNodesTreeBuilder
*Builder
) const override
{
134 return llvm::any_of(NameMatchers
, [&Node
](const NameMatcher
&NM
) {
135 return NM
.match(Node
);
140 std::vector
<NameMatcher
> NameMatchers
;
143 // Returns a matcher that matches NamedDecl's against a list of provided regular
144 // expressions. If a regular expression contains starts ':' the NamedDecl's
145 // qualified name will be used for matching, otherwise its name will be used.
146 inline ::clang::ast_matchers::internal::Matcher
<NamedDecl
>
147 matchesAnyListedName(llvm::ArrayRef
<StringRef
> NameList
) {
148 return ::clang::ast_matchers::internal::makeMatcher(
149 new MatchesAnyListedNameMatcher(NameList
));
152 // Predicate that verify if statement is not identical to one bound to ID node.
153 struct NotIdenticalStatementsPredicate
{
155 operator()(const clang::ast_matchers::internal::BoundNodesMap
&Nodes
) const;
158 ::clang::DynTypedNode Node
;
162 // Checks if statement is identical (utils::areStatementsIdentical) to one bound
164 AST_MATCHER_P(Stmt
, isStatementIdenticalToBoundNode
, std::string
, ID
) {
165 NotIdenticalStatementsPredicate Predicate
{
166 ID
, ::clang::DynTypedNode::create(Node
), &(Finder
->getASTContext())};
167 return Builder
->removeBindings(Predicate
);
170 // A matcher implementation that matches a list of type name regular expressions
171 // against a QualType.
172 class MatchesAnyListedTypeNameMatcher
173 : public ast_matchers::internal::MatcherInterface
<QualType
> {
175 explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef
<StringRef
> NameList
);
176 ~MatchesAnyListedTypeNameMatcher() override
;
178 const QualType
&Node
, ast_matchers::internal::ASTMatchFinder
*Finder
,
179 ast_matchers::internal::BoundNodesTreeBuilder
*Builder
) const override
;
182 std::vector
<llvm::Regex
> NameMatchers
;
185 // Returns a matcher that matches QualType against a list of provided regular.
186 inline ::clang::ast_matchers::internal::Matcher
<QualType
>
187 matchesAnyListedTypeName(llvm::ArrayRef
<StringRef
> NameList
) {
188 return ::clang::ast_matchers::internal::makeMatcher(
189 new MatchesAnyListedTypeNameMatcher(NameList
));
192 } // namespace clang::tidy::matchers
194 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H