clang-tools 24.0.0git
clang-tidy/utils/Matchers.h
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
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(CXXMethodDecl, isStatic) { return Node.isStatic(); }
26
27AST_MATCHER(FunctionDecl, isOverloadedOperator) {
28 return Node.isOverloadedOperator();
29}
30
31AST_MATCHER(Decl, isOutOfLine) { return Node.isOutOfLine(); }
32
33AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); }
34
35AST_MATCHER(Expr, isMacroID) { return Node.getExprLoc().isMacroID(); }
36
37AST_MATCHER(QualType, isExpensiveToCopy) {
38 std::optional<bool> IsExpensive =
39 utils::type_traits::isExpensiveToCopy(Node, Finder->getASTContext());
40 return IsExpensive && *IsExpensive;
41}
42
43AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {
45 Node, Finder->getASTContext());
46}
47
48AST_MATCHER(QualType, isTriviallyDestructible) {
50}
51
52// Returns QualType matcher for references to const.
53AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst) {
54 using namespace ast_matchers;
55 return referenceType(pointee(qualType(isConstQualified())));
56}
57
58// Returns QualType matcher for pointers to const.
59AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
60 using namespace ast_matchers;
61 return pointerType(pointee(qualType(isConstQualified())));
62}
63
64// Returns QualType matcher for target char type only.
65AST_MATCHER(QualType, isSimpleChar) {
66 const auto *ActualType = Node.getTypePtr();
67 return ActualType &&
68 (ActualType->isSpecificBuiltinType(BuiltinType::Char_S) ||
69 ActualType->isSpecificBuiltinType(BuiltinType::Char_U));
70}
71
72AST_MATCHER(Expr, hasUnevaluatedContext) {
73 if (isa<CXXNoexceptExpr>(Node) || isa<RequiresExpr>(Node))
74 return true;
75 if (const auto *UnaryExpr = dyn_cast<UnaryExprOrTypeTraitExpr>(&Node)) {
76 switch (UnaryExpr->getKind()) {
77 case UETT_SizeOf:
78 case UETT_AlignOf:
79 return true;
80 default:
81 return false;
82 }
83 }
84 if (const auto *TypeIDExpr = dyn_cast<CXXTypeidExpr>(&Node))
85 return !TypeIDExpr->isPotentiallyEvaluated();
86 return false;
87}
88
89// A matcher implementation that matches a list of type name regular expressions
90// against a NamedDecl. If a regular expression contains the substring "::"
91// matching will occur against the qualified name, otherwise only the typename.
94public:
96 llvm::ArrayRef<StringRef> NameList) {
97 llvm::transform(NameList, std::back_inserter(NameMatchers),
98 [](const StringRef Name) { return NameMatcher(Name); });
99 }
100
102 llvm::Regex Regex;
103 enum class MatchMode {
104 // Match against the unqualified name because the regular expression
105 // does not contain ":".
106 MatchUnqualified,
107 // Match against the qualified name because the regular expression
108 // contains ":" suggesting name and namespace should be matched.
109 MatchQualified,
110 // Match against the fully qualified name because the regular expression
111 // starts with ":".
112 MatchFullyQualified,
113 };
114 MatchMode Mode;
115
116 public:
117 NameMatcher(const StringRef Regex)
118 : Regex(Regex), Mode(determineMatchMode(Regex)) {}
119
120 bool match(const NamedDecl &ND) const {
121 switch (Mode) {
122 case MatchMode::MatchQualified:
123 return Regex.match(ND.getQualifiedNameAsString());
124 case MatchMode::MatchFullyQualified:
125 return Regex.match("::" + ND.getQualifiedNameAsString());
126 default:
127 if (const IdentifierInfo *II = ND.getIdentifier())
128 return Regex.match(II->getName());
129 return false;
130 }
131 }
132
133 private:
134 MatchMode determineMatchMode(StringRef Regex) {
135 if (Regex.starts_with(':') || Regex.starts_with("^:"))
136 return MatchMode::MatchFullyQualified;
137 return Regex.contains(':') ? MatchMode::MatchQualified
138 : MatchMode::MatchUnqualified;
139 }
140 };
141
143 const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
144 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
145 return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) {
146 return NM.match(Node);
147 });
148 }
149
150private:
151 std::vector<NameMatcher> NameMatchers;
152};
153
154// Returns a matcher that matches NamedDecl's against a list of provided regular
155// expressions. If a regular expression contains starts ':' the NamedDecl's
156// qualified name will be used for matching, otherwise its name will be used.
157inline ::clang::ast_matchers::internal::Matcher<NamedDecl>
158matchesAnyListedRegexName(llvm::ArrayRef<StringRef> NameList) {
159 return ::clang::ast_matchers::internal::Matcher(
161}
162
163// Predicate that verify if statement is not identical to one bound to ID node.
165 bool
166 operator()(const clang::ast_matchers::internal::BoundNodesMap &Nodes) const;
167
168 std::string ID;
169 ::clang::DynTypedNode Node;
170 ASTContext *Context;
171};
172
173// Checks if statement is identical (utils::areStatementsIdentical) to one bound
174// to ID node.
175AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID) {
176 const NotIdenticalStatementsPredicate Predicate{
177 ID, ::clang::DynTypedNode::create(Node), &Finder->getASTContext()};
178 return Builder->removeBindings(Predicate);
179}
180
181// A matcher implementation that matches a list of type name regular expressions
182// against a QualType.
185public:
186 explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef<StringRef> NameList,
187 bool CanonicalTypes);
189 bool matches(
190 const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder,
191 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override;
192
193private:
194 std::vector<llvm::Regex> NameMatchers;
195 bool CanonicalTypes;
196};
197
198// Returns a matcher that matches QualType against a list of provided regular.
199inline ::clang::ast_matchers::internal::Matcher<QualType>
200matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList,
201 bool CanonicalTypes) {
202 return ::clang::ast_matchers::internal::Matcher(
203 new MatchesAnyListedTypeNameMatcher(NameList, CanonicalTypes));
204}
205inline ::clang::ast_matchers::internal::Matcher<QualType>
206matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList) {
207 return matchesAnyListedTypeName(NameList, true);
208}
209
210} // namespace clang::tidy::matchers
211
212#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
bool matches(const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder, ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override
MatchesAnyListedRegexNameMatcher(llvm::ArrayRef< StringRef > NameList)
MatchesAnyListedTypeNameMatcher(llvm::ArrayRef< StringRef > NameList, bool CanonicalTypes)
Definition Matchers.cpp:20
bool matches(const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder, ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override
Definition Matchers.cpp:27
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
inline ::clang::ast_matchers::internal::Matcher< QualType > matchesAnyListedTypeName(llvm::ArrayRef< StringRef > NameList, bool CanonicalTypes)
AST_MATCHER(BinaryOperator, isRelationalOperator)
AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedRegexName(llvm::ArrayRef< StringRef > NameList)
bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, const ASTContext &Context)
Returns true if RecordDecl is trivially default constructible.
std::optional< bool > isExpensiveToCopy(QualType Type, const ASTContext &Context)
Returns true if Type is expensive to copy.
bool isTriviallyDestructible(QualType Type)
Returns true if Type is trivially destructible.
bool operator()(const clang::ast_matchers::internal::BoundNodesMap &Nodes) const
Definition Matchers.cpp:14