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/ASTMatchers/ASTMatchers.h"
14 
15 namespace clang {
16 namespace tidy {
17 namespace matchers {
18 
AST_MATCHER(BinaryOperator,isRelationalOperator)19 AST_MATCHER(BinaryOperator, isRelationalOperator) {
20   return Node.isRelationalOp();
21 }
22 
AST_MATCHER(BinaryOperator,isEqualityOperator)23 AST_MATCHER(BinaryOperator, isEqualityOperator) { return Node.isEqualityOp(); }
24 
AST_MATCHER(QualType,isExpensiveToCopy)25 AST_MATCHER(QualType, isExpensiveToCopy) {
26   llvm::Optional<bool> IsExpensive =
27       utils::type_traits::isExpensiveToCopy(Node, Finder->getASTContext());
28   return IsExpensive && *IsExpensive;
29 }
30 
AST_MATCHER(RecordDecl,isTriviallyDefaultConstructible)31 AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {
32   return utils::type_traits::recordIsTriviallyDefaultConstructible(
33       Node, Finder->getASTContext());
34 }
35 
AST_MATCHER(QualType,isTriviallyDestructible)36 AST_MATCHER(QualType, isTriviallyDestructible) {
37   return utils::type_traits::isTriviallyDestructible(Node);
38 }
39 
40 // Returns QualType matcher for references to const.
AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher,isReferenceToConst)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.
AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher,isPointerToConst)47 AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
48   using namespace ast_matchers;
49   return pointerType(pointee(qualType(isConstQualified())));
50 }
51 
52 // A matcher implementation that matches a list of type name regular expressions
53 // against a NamedDecl. If a regular expression contains the substring "::"
54 // matching will occur against the qualified name, otherwise only the typename.
55 class MatchesAnyListedNameMatcher
56     : public ast_matchers::internal::MatcherInterface<NamedDecl> {
57 public:
MatchesAnyListedNameMatcher(llvm::ArrayRef<std::string> NameList)58   explicit MatchesAnyListedNameMatcher(llvm::ArrayRef<std::string> NameList) {
59     std::transform(
60         NameList.begin(), NameList.end(), std::back_inserter(NameMatchers),
61         [](const llvm::StringRef Name) { return NameMatcher(Name); });
62   }
matches(const NamedDecl & Node,ast_matchers::internal::ASTMatchFinder * Finder,ast_matchers::internal::BoundNodesTreeBuilder * Builder)63   bool matches(
64       const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
65       ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
66     return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) {
67       return NM.match(Node);
68     });
69   }
70 
71 private:
72   class NameMatcher {
73     llvm::Regex Regex;
74     enum class MatchMode {
75       // Match against the unqualified name because the regular expression
76       // does not contain ":".
77       MatchUnqualified,
78       // Match against the qualified name because the regular expression
79       // contains ":" suggesting name and namespace should be matched.
80       MatchQualified,
81       // Match against the fully qualified name because the regular expression
82       // starts with ":".
83       MatchFullyQualified,
84     };
85     MatchMode Mode;
86 
87   public:
NameMatcher(const llvm::StringRef Regex)88     NameMatcher(const llvm::StringRef Regex)
89         : Regex(Regex), Mode(determineMatchMode(Regex)) {}
90 
match(const NamedDecl & ND)91     bool match(const NamedDecl &ND) const {
92       switch (Mode) {
93       case MatchMode::MatchQualified:
94         return Regex.match(ND.getQualifiedNameAsString());
95       case MatchMode::MatchFullyQualified:
96         return Regex.match("::" + ND.getQualifiedNameAsString());
97       default:
98         return Regex.match(ND.getName());
99       }
100     }
101 
102   private:
determineMatchMode(llvm::StringRef Regex)103     MatchMode determineMatchMode(llvm::StringRef Regex) {
104       if (Regex.startswith(":") || Regex.startswith("^:")) {
105         return MatchMode::MatchFullyQualified;
106       }
107       return Regex.contains(":") ? MatchMode::MatchQualified
108                                  : MatchMode::MatchUnqualified;
109     }
110   };
111 
112   std::vector<NameMatcher> NameMatchers;
113 };
114 
115 // Returns a matcher that matches NamedDecl's against a list of provided regular
116 // expressions. If a regular expression contains starts ':' the NamedDecl's
117 // qualified name will be used for matching, otherwise its name will be used.
118 inline ::clang::ast_matchers::internal::Matcher<NamedDecl>
matchesAnyListedName(llvm::ArrayRef<std::string> NameList)119 matchesAnyListedName(llvm::ArrayRef<std::string> NameList) {
120   return ::clang::ast_matchers::internal::makeMatcher(
121       new MatchesAnyListedNameMatcher(NameList));
122 }
123 
124 } // namespace matchers
125 } // namespace tidy
126 } // namespace clang
127 
128 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
129