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 17 namespace clang::tidy::matchers { 18 19 AST_MATCHER(BinaryOperator, isRelationalOperator) { 20 return Node.isRelationalOp(); 21 } 22 23 AST_MATCHER(BinaryOperator, isEqualityOperator) { return Node.isEqualityOp(); } 24 25 AST_MATCHER(QualType, isExpensiveToCopy) { 26 std::optional<bool> IsExpensive = 27 utils::type_traits::isExpensiveToCopy(Node, Finder->getASTContext()); 28 return IsExpensive && *IsExpensive; 29 } 30 31 AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) { 32 return utils::type_traits::recordIsTriviallyDefaultConstructible( 33 Node, Finder->getASTContext()); 34 } 35 36 AST_MATCHER(QualType, isTriviallyDestructible) { 37 return utils::type_traits::isTriviallyDestructible(Node); 38 } 39 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()))); 44 } 45 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()))); 50 } 51 52 // Returns QualType matcher for target char type only. 53 AST_MATCHER(QualType, isSimpleChar) { 54 const auto ActualType = Node.getTypePtr(); 55 return ActualType && 56 (ActualType->isSpecificBuiltinType(BuiltinType::Char_S) || 57 ActualType->isSpecificBuiltinType(BuiltinType::Char_U)); 58 } 59 60 AST_MATCHER(Expr, hasUnevaluatedContext) { 61 if (isa<CXXNoexceptExpr>(Node) || isa<RequiresExpr>(Node)) 62 return true; 63 if (const auto *UnaryExpr = dyn_cast<UnaryExprOrTypeTraitExpr>(&Node)) { 64 switch (UnaryExpr->getKind()) { 65 case UETT_SizeOf: 66 case UETT_AlignOf: 67 return true; 68 default: 69 return false; 70 } 71 } 72 if (const auto *TypeIDExpr = dyn_cast<CXXTypeidExpr>(&Node)) 73 return !TypeIDExpr->isPotentiallyEvaluated(); 74 return false; 75 } 76 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> { 82 public: 83 explicit MatchesAnyListedNameMatcher(llvm::ArrayRef<StringRef> NameList) { 84 std::transform( 85 NameList.begin(), NameList.end(), std::back_inserter(NameMatchers), 86 [](const llvm::StringRef Name) { return NameMatcher(Name); }); 87 } 88 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(ND.getQualifiedNameAsString()); 112 case MatchMode::MatchFullyQualified: 113 return Regex.match("::" + ND.getQualifiedNameAsString()); 114 default: 115 if (const IdentifierInfo *II = ND.getIdentifier()) 116 return Regex.match(II->getName()); 117 return false; 118 } 119 } 120 121 private: 122 MatchMode determineMatchMode(llvm::StringRef Regex) { 123 if (Regex.starts_with(":") || Regex.starts_with("^:")) { 124 return MatchMode::MatchFullyQualified; 125 } 126 return Regex.contains(":") ? MatchMode::MatchQualified 127 : MatchMode::MatchUnqualified; 128 } 129 }; 130 131 bool matches( 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); 136 }); 137 } 138 139 private: 140 std::vector<NameMatcher> NameMatchers; 141 }; 142 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)); 150 } 151 152 // Predicate that verify if statement is not identical to one bound to ID node. 153 struct NotIdenticalStatementsPredicate { 154 bool 155 operator()(const clang::ast_matchers::internal::BoundNodesMap &Nodes) const; 156 157 std::string ID; 158 ::clang::DynTypedNode Node; 159 ASTContext *Context; 160 }; 161 162 // Checks if statement is identical (utils::areStatementsIdentical) to one bound 163 // to ID node. 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); 168 } 169 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> { 174 public: 175 explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef<StringRef> NameList); 176 ~MatchesAnyListedTypeNameMatcher() override; 177 bool matches( 178 const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder, 179 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override; 180 181 private: 182 std::vector<llvm::Regex> NameMatchers; 183 }; 184 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)); 190 } 191 192 } // namespace clang::tidy::matchers 193 194 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H 195