1//===--- Matchers.h - 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//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
11
12#include "TypeTraits.h"
13#include "clang/AST/ExprConcepts.h"
14#include "clang/ASTMatchers/ASTMatchers.h"
15#include <optional>
16
17namespace clang::tidy::matchers {
18
19AST_MATCHER(BinaryOperator, isRelationalOperator) {
20 return Node.isRelationalOp();
21}
22
23AST_MATCHER(BinaryOperator, isEqualityOperator) { return Node.isEqualityOp(); }
24
25AST_MATCHER(QualType, isExpensiveToCopy) {
26 std::optional<bool> IsExpensive =
27 utils::type_traits::isExpensiveToCopy(Type: Node, Context: Finder->getASTContext());
28 return IsExpensive && *IsExpensive;
29}
30
31AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {
32 return utils::type_traits::recordIsTriviallyDefaultConstructible(
33 RecordDecl: Node, Context: Finder->getASTContext());
34}
35
36AST_MATCHER(QualType, isTriviallyDestructible) {
37 return utils::type_traits::isTriviallyDestructible(Type: Node);
38}
39
40// Returns QualType matcher for references to const.
41AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst) {
42 using namespace ast_matchers;
43 return referenceType(pointee(qualType(isConstQualified())));
44}
45
46// Returns QualType matcher for pointers to const.
47AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
48 using namespace ast_matchers;
49 return pointerType(pointee(qualType(isConstQualified())));
50}
51
52AST_MATCHER(Expr, hasUnevaluatedContext) {
53 if (isa<CXXNoexceptExpr>(Val: Node) || isa<RequiresExpr>(Val: Node))
54 return true;
55 if (const auto *UnaryExpr = dyn_cast<UnaryExprOrTypeTraitExpr>(Val: &Node)) {
56 switch (UnaryExpr->getKind()) {
57 case UETT_SizeOf:
58 case UETT_AlignOf:
59 return true;
60 default:
61 return false;
62 }
63 }
64 if (const auto *TypeIDExpr = dyn_cast<CXXTypeidExpr>(Val: &Node))
65 return !TypeIDExpr->isPotentiallyEvaluated();
66 return false;
67}
68
69// A matcher implementation that matches a list of type name regular expressions
70// against a NamedDecl. If a regular expression contains the substring "::"
71// matching will occur against the qualified name, otherwise only the typename.
72class MatchesAnyListedNameMatcher
73 : public ast_matchers::internal::MatcherInterface<NamedDecl> {
74public:
75 explicit MatchesAnyListedNameMatcher(llvm::ArrayRef<StringRef> NameList) {
76 std::transform(
77 first: NameList.begin(), last: NameList.end(), result: std::back_inserter(x&: NameMatchers),
78 unary_op: [](const llvm::StringRef Name) { return NameMatcher(Name); });
79 }
80 bool matches(
81 const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
82 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
83 return llvm::any_of(Range: NameMatchers, P: [&Node](const NameMatcher &NM) {
84 return NM.match(ND: Node);
85 });
86 }
87
88private:
89 class NameMatcher {
90 llvm::Regex Regex;
91 enum class MatchMode {
92 // Match against the unqualified name because the regular expression
93 // does not contain ":".
94 MatchUnqualified,
95 // Match against the qualified name because the regular expression
96 // contains ":" suggesting name and namespace should be matched.
97 MatchQualified,
98 // Match against the fully qualified name because the regular expression
99 // starts with ":".
100 MatchFullyQualified,
101 };
102 MatchMode Mode;
103
104 public:
105 NameMatcher(const llvm::StringRef Regex)
106 : Regex(Regex), Mode(determineMatchMode(Regex)) {}
107
108 bool match(const NamedDecl &ND) const {
109 switch (Mode) {
110 case MatchMode::MatchQualified:
111 return Regex.match(String: ND.getQualifiedNameAsString());
112 case MatchMode::MatchFullyQualified:
113 return Regex.match(String: "::" + ND.getQualifiedNameAsString());
114 default:
115 if (const IdentifierInfo *II = ND.getIdentifier())
116 return Regex.match(String: II->getName());
117 return false;
118 }
119 }
120
121 private:
122 MatchMode determineMatchMode(llvm::StringRef Regex) {
123 if (Regex.starts_with(Prefix: ":") || Regex.starts_with(Prefix: "^:")) {
124 return MatchMode::MatchFullyQualified;
125 }
126 return Regex.contains(Other: ":") ? MatchMode::MatchQualified
127 : MatchMode::MatchUnqualified;
128 }
129 };
130
131 std::vector<NameMatcher> NameMatchers;
132};
133
134// Returns a matcher that matches NamedDecl's against a list of provided regular
135// expressions. If a regular expression contains starts ':' the NamedDecl's
136// qualified name will be used for matching, otherwise its name will be used.
137inline ::clang::ast_matchers::internal::Matcher<NamedDecl>
138matchesAnyListedName(llvm::ArrayRef<StringRef> NameList) {
139 return ::clang::ast_matchers::internal::makeMatcher(
140 Implementation: new MatchesAnyListedNameMatcher(NameList));
141}
142
143// Predicate that verify if statement is not identical to one bound to ID node.
144struct NotIdenticalStatementsPredicate {
145 bool
146 operator()(const clang::ast_matchers::internal::BoundNodesMap &Nodes) const;
147
148 std::string ID;
149 ::clang::DynTypedNode Node;
150 ASTContext *Context;
151};
152
153// Checks if statement is identical (utils::areStatementsIdentical) to one bound
154// to ID node.
155AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID) {
156 NotIdenticalStatementsPredicate Predicate{
157 ID, ::clang::DynTypedNode::create(Node), &(Finder->getASTContext())};
158 return Builder->removeBindings(Predicate);
159}
160
161// A matcher implementation that matches a list of type name regular expressions
162// against a QualType.
163class MatchesAnyListedTypeNameMatcher
164 : public ast_matchers::internal::MatcherInterface<QualType> {
165public:
166 explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef<StringRef> NameList);
167 ~MatchesAnyListedTypeNameMatcher() override;
168 bool matches(
169 const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder,
170 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override;
171
172private:
173 std::vector<llvm::Regex> NameMatchers;
174};
175
176// Returns a matcher that matches QualType against a list of provided regular.
177inline ::clang::ast_matchers::internal::Matcher<QualType>
178matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList) {
179 return ::clang::ast_matchers::internal::makeMatcher(
180 Implementation: new MatchesAnyListedTypeNameMatcher(NameList));
181}
182
183} // namespace clang::tidy::matchers
184
185#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
186

source code of clang-tools-extra/clang-tidy/utils/Matchers.h