202 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H11 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(Node, Finder->getASTContext());28 return IsExpensive && *IsExpensive;29}30 31AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {32 return utils::type_traits::recordIsTriviallyDefaultConstructible(33 Node, Finder->getASTContext());34}35 36AST_MATCHER(QualType, isTriviallyDestructible) {37 return utils::type_traits::isTriviallyDestructible(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 52// Returns QualType matcher for target char type only.53AST_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 60AST_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 expressions78// against a NamedDecl. If a regular expression contains the substring "::"79// matching will occur against the qualified name, otherwise only the typename.80class MatchesAnyListedNameMatcher81 : public ast_matchers::internal::MatcherInterface<NamedDecl> {82public: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 expression93 // does not contain ":".94 MatchUnqualified,95 // Match against the qualified name because the regular expression96 // contains ":" suggesting name and namespace should be matched.97 MatchQualified,98 // Match against the fully qualified name because the regular expression99 // 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::MatchQualified127 : 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 139private:140 std::vector<NameMatcher> NameMatchers;141};142 143// Returns a matcher that matches NamedDecl's against a list of provided regular144// expressions. If a regular expression contains starts ':' the NamedDecl's145// qualified name will be used for matching, otherwise its name will be used.146inline ::clang::ast_matchers::internal::Matcher<NamedDecl>147matchesAnyListedName(llvm::ArrayRef<StringRef> NameList) {148 return ::clang::ast_matchers::internal::Matcher(149 new MatchesAnyListedNameMatcher(NameList));150}151 152// Predicate that verify if statement is not identical to one bound to ID node.153struct NotIdenticalStatementsPredicate {154 bool155 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 bound163// to ID node.164AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID) {165 const 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 expressions171// against a QualType.172class MatchesAnyListedTypeNameMatcher173 : public ast_matchers::internal::MatcherInterface<QualType> {174public:175 explicit MatchesAnyListedTypeNameMatcher(llvm::ArrayRef<StringRef> NameList,176 bool CanonicalTypes);177 ~MatchesAnyListedTypeNameMatcher() override;178 bool matches(179 const QualType &Node, ast_matchers::internal::ASTMatchFinder *Finder,180 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override;181 182private:183 std::vector<llvm::Regex> NameMatchers;184 bool CanonicalTypes;185};186 187// Returns a matcher that matches QualType against a list of provided regular.188inline ::clang::ast_matchers::internal::Matcher<QualType>189matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList,190 bool CanonicalTypes) {191 return ::clang::ast_matchers::internal::Matcher(192 new MatchesAnyListedTypeNameMatcher(NameList, CanonicalTypes));193}194inline ::clang::ast_matchers::internal::Matcher<QualType>195matchesAnyListedTypeName(llvm::ArrayRef<StringRef> NameList) {196 return matchesAnyListedTypeName(NameList, true);197}198 199} // namespace clang::tidy::matchers200 201#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H202