File indexing completed on 2026-05-10 08:36:22
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
0010 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
0011
0012 #include "TypeTraits.h"
0013 #include "clang/AST/ExprConcepts.h"
0014 #include "clang/ASTMatchers/ASTMatchers.h"
0015 #include <optional>
0016
0017 namespace clang::tidy::matchers {
0018
0019 AST_MATCHER(BinaryOperator, isRelationalOperator) {
0020 return Node.isRelationalOp();
0021 }
0022
0023 AST_MATCHER(BinaryOperator, isEqualityOperator) { return Node.isEqualityOp(); }
0024
0025 AST_MATCHER(QualType, isExpensiveToCopy) {
0026 std::optional<bool> IsExpensive =
0027 utils::type_traits::isExpensiveToCopy(Node, Finder->getASTContext());
0028 return IsExpensive && *IsExpensive;
0029 }
0030
0031 AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {
0032 return utils::type_traits::recordIsTriviallyDefaultConstructible(
0033 Node, Finder->getASTContext());
0034 }
0035
0036 AST_MATCHER(QualType, isTriviallyDestructible) {
0037 return utils::type_traits::isTriviallyDestructible(Node);
0038 }
0039
0040
0041 AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst) {
0042 using namespace ast_matchers;
0043 return referenceType(pointee(qualType(isConstQualified())));
0044 }
0045
0046
0047 AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
0048 using namespace ast_matchers;
0049 return pointerType(pointee(qualType(isConstQualified())));
0050 }
0051
0052
0053 AST_MATCHER(QualType, isSimpleChar) {
0054 const auto ActualType = Node.getTypePtr();
0055 return ActualType &&
0056 (ActualType->isSpecificBuiltinType(BuiltinType::Char_S) ||
0057 ActualType->isSpecificBuiltinType(BuiltinType::Char_U));
0058 }
0059
0060 AST_MATCHER(Expr, hasUnevaluatedContext) {
0061 if (isa<CXXNoexceptExpr>(Node) || isa<RequiresExpr>(Node))
0062 return true;
0063 if (const auto *UnaryExpr = dyn_cast<UnaryExprOrTypeTraitExpr>(&Node)) {
0064 switch (UnaryExpr->getKind()) {
0065 case UETT_SizeOf:
0066 case UETT_AlignOf:
0067 return true;
0068 default:
0069 return false;
0070 }
0071 }
0072 if (const auto *TypeIDExpr = dyn_cast<CXXTypeidExpr>(&Node))
0073 return !TypeIDExpr->isPotentiallyEvaluated();
0074 return false;
0075 }
0076
0077
0078
0079
0080 class MatchesAnyListedNameMatcher
0081 : public ast_matchers::internal::MatcherInterface<NamedDecl> {
0082 public:
0083 explicit MatchesAnyListedNameMatcher(llvm::ArrayRef<StringRef> NameList) {
0084 std::transform(
0085 NameList.begin(), NameList.end(), std::back_inserter(NameMatchers),
0086 [](const llvm::StringRef Name) { return NameMatcher(Name); });
0087 }
0088
0089 class NameMatcher {
0090 llvm::Regex Regex;
0091 enum class MatchMode {
0092
0093
0094 MatchUnqualified,
0095
0096
0097 MatchQualified,
0098
0099
0100 MatchFullyQualified,
0101 };
0102 MatchMode Mode;
0103
0104 public:
0105 NameMatcher(const llvm::StringRef Regex)
0106 : Regex(Regex), Mode(determineMatchMode(Regex)) {}
0107
0108 bool match(const NamedDecl &ND) const {
0109 switch (Mode) {
0110 case MatchMode::MatchQualified:
0111 return Regex.match(ND.getQualifiedNameAsString());
0112 case MatchMode::MatchFullyQualified:
0113 return Regex.match("::" + ND.getQualifiedNameAsString());
0114 default:
0115 if (const IdentifierInfo *II = ND.getIdentifier())
0116 return Regex.match(II->getName());
0117 return false;
0118 }
0119 }
0120
0121 private:
0122 MatchMode determineMatchMode(llvm::StringRef Regex) {
0123 if (Regex.starts_with(":") || Regex.starts_with("^:")) {
0124 return MatchMode::MatchFullyQualified;
0125 }
0126 return Regex.contains(":") ? MatchMode::MatchQualified
0127 : MatchMode::MatchUnqualified;
0128 }
0129 };
0130
0131 bool matches(
0132 const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
0133 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
0134 return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) {
0135 return NM.match(Node);
0136 });
0137 }
0138
0139 private:
0140 std::vector<NameMatcher> NameMatchers;
0141 };
0142
0143
0144
0145
0146 inline ::clang::ast_matchers::internal::Matcher<NamedDecl>
0147 matchesAnyListedName(llvm::ArrayRef<StringRef> NameList) {
0148 return ::clang::ast_matchers::internal::makeMatcher(
0149 new MatchesAnyListedNameMatcher(NameList));
0150 }
0151
0152
0153 struct NotIdenticalStatementsPredicate {
0154 bool
0155 operator()(const clang::ast_matchers::internal::BoundNodesMap &Nodes) const;
0156
0157 std::string ID;
0158 ::clang::DynTypedNode Node;
0159 ASTContext *Context;
0160 };
0161
0162
0163
0164 AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID) {
0165 NotIdenticalStatementsPredicate Predicate{
0166 ID, ::clang::DynTypedNode::create(Node), &(Finder->getASTContext())};
0167 return Builder->removeBindings(Predicate);
0168 }
0169
0170
0171
0172 class MatchesAnyListedTypeNameMatcher
0173 : public ast_matchers::internal::MatcherInterface<QualType> {
0174 public:
0175 explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef<StringRef> NameList);
0176 ~MatchesAnyListedTypeNameMatcher() override;
0177 bool matches(
0178 const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder,
0179 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override;
0180
0181 private:
0182 std::vector<llvm::Regex> NameMatchers;
0183 };
0184
0185
0186 inline ::clang::ast_matchers::internal::Matcher<QualType>
0187 matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList) {
0188 return ::clang::ast_matchers::internal::makeMatcher(
0189 new MatchesAnyListedTypeNameMatcher(NameList));
0190 }
0191
0192 }
0193
0194 #endif