xref: /freebsd-src/contrib/llvm-project/clang/lib/ASTMatchers/GtestMatchers.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===- GtestMatchers.cpp - AST Matchers for Gtest ---------------*- C++ -*-===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric 
9*5ffd83dbSDimitry Andric #include "clang/ASTMatchers/GtestMatchers.h"
10*5ffd83dbSDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
11*5ffd83dbSDimitry Andric #include "clang/AST/ASTConsumer.h"
12*5ffd83dbSDimitry Andric #include "clang/AST/ASTContext.h"
13*5ffd83dbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
14*5ffd83dbSDimitry Andric #include "llvm/ADT/DenseMap.h"
15*5ffd83dbSDimitry Andric #include "llvm/ADT/StringMap.h"
16*5ffd83dbSDimitry Andric #include "llvm/Support/Timer.h"
17*5ffd83dbSDimitry Andric #include <deque>
18*5ffd83dbSDimitry Andric #include <memory>
19*5ffd83dbSDimitry Andric #include <set>
20*5ffd83dbSDimitry Andric 
21*5ffd83dbSDimitry Andric namespace clang {
22*5ffd83dbSDimitry Andric namespace ast_matchers {
23*5ffd83dbSDimitry Andric 
24*5ffd83dbSDimitry Andric static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) {
25*5ffd83dbSDimitry Andric   switch (Cmp) {
26*5ffd83dbSDimitry Andric     case GtestCmp::Eq:
27*5ffd83dbSDimitry Andric       return cxxMethodDecl(hasName("Compare"),
28*5ffd83dbSDimitry Andric                            ofClass(cxxRecordDecl(isSameOrDerivedFrom(
29*5ffd83dbSDimitry Andric                                hasName("::testing::internal::EqHelper")))));
30*5ffd83dbSDimitry Andric     case GtestCmp::Ne:
31*5ffd83dbSDimitry Andric       return functionDecl(hasName("::testing::internal::CmpHelperNE"));
32*5ffd83dbSDimitry Andric     case GtestCmp::Ge:
33*5ffd83dbSDimitry Andric       return functionDecl(hasName("::testing::internal::CmpHelperGE"));
34*5ffd83dbSDimitry Andric     case GtestCmp::Gt:
35*5ffd83dbSDimitry Andric       return functionDecl(hasName("::testing::internal::CmpHelperGT"));
36*5ffd83dbSDimitry Andric     case GtestCmp::Le:
37*5ffd83dbSDimitry Andric       return functionDecl(hasName("::testing::internal::CmpHelperLE"));
38*5ffd83dbSDimitry Andric     case GtestCmp::Lt:
39*5ffd83dbSDimitry Andric       return functionDecl(hasName("::testing::internal::CmpHelperLT"));
40*5ffd83dbSDimitry Andric   }
41*5ffd83dbSDimitry Andric   llvm_unreachable("Unhandled GtestCmp enum");
42*5ffd83dbSDimitry Andric }
43*5ffd83dbSDimitry Andric 
44*5ffd83dbSDimitry Andric static llvm::StringRef getAssertMacro(GtestCmp Cmp) {
45*5ffd83dbSDimitry Andric   switch (Cmp) {
46*5ffd83dbSDimitry Andric     case GtestCmp::Eq:
47*5ffd83dbSDimitry Andric       return "ASSERT_EQ";
48*5ffd83dbSDimitry Andric     case GtestCmp::Ne:
49*5ffd83dbSDimitry Andric       return "ASSERT_NE";
50*5ffd83dbSDimitry Andric     case GtestCmp::Ge:
51*5ffd83dbSDimitry Andric       return "ASSERT_GE";
52*5ffd83dbSDimitry Andric     case GtestCmp::Gt:
53*5ffd83dbSDimitry Andric       return "ASSERT_GT";
54*5ffd83dbSDimitry Andric     case GtestCmp::Le:
55*5ffd83dbSDimitry Andric       return "ASSERT_LE";
56*5ffd83dbSDimitry Andric     case GtestCmp::Lt:
57*5ffd83dbSDimitry Andric       return "ASSERT_LT";
58*5ffd83dbSDimitry Andric   }
59*5ffd83dbSDimitry Andric   llvm_unreachable("Unhandled GtestCmp enum");
60*5ffd83dbSDimitry Andric }
61*5ffd83dbSDimitry Andric 
62*5ffd83dbSDimitry Andric static llvm::StringRef getExpectMacro(GtestCmp Cmp) {
63*5ffd83dbSDimitry Andric   switch (Cmp) {
64*5ffd83dbSDimitry Andric     case GtestCmp::Eq:
65*5ffd83dbSDimitry Andric       return "EXPECT_EQ";
66*5ffd83dbSDimitry Andric     case GtestCmp::Ne:
67*5ffd83dbSDimitry Andric       return "EXPECT_NE";
68*5ffd83dbSDimitry Andric     case GtestCmp::Ge:
69*5ffd83dbSDimitry Andric       return "EXPECT_GE";
70*5ffd83dbSDimitry Andric     case GtestCmp::Gt:
71*5ffd83dbSDimitry Andric       return "EXPECT_GT";
72*5ffd83dbSDimitry Andric     case GtestCmp::Le:
73*5ffd83dbSDimitry Andric       return "EXPECT_LE";
74*5ffd83dbSDimitry Andric     case GtestCmp::Lt:
75*5ffd83dbSDimitry Andric       return "EXPECT_LT";
76*5ffd83dbSDimitry Andric   }
77*5ffd83dbSDimitry Andric   llvm_unreachable("Unhandled GtestCmp enum");
78*5ffd83dbSDimitry Andric }
79*5ffd83dbSDimitry Andric 
80*5ffd83dbSDimitry Andric // In general, AST matchers cannot match calls to macros. However, we can
81*5ffd83dbSDimitry Andric // simulate such matches if the macro definition has identifiable elements that
82*5ffd83dbSDimitry Andric // themselves can be matched. In that case, we can match on those elements and
83*5ffd83dbSDimitry Andric // then check that the match occurs within an expansion of the desired
84*5ffd83dbSDimitry Andric // macro. The more uncommon the identified elements, the more efficient this
85*5ffd83dbSDimitry Andric // process will be.
86*5ffd83dbSDimitry Andric //
87*5ffd83dbSDimitry Andric // We use this approach to implement the derived matchers gtestAssert and
88*5ffd83dbSDimitry Andric // gtestExpect.
89*5ffd83dbSDimitry Andric internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left,
90*5ffd83dbSDimitry Andric                                             StatementMatcher Right) {
91*5ffd83dbSDimitry Andric   return callExpr(callee(getComparisonDecl(Cmp)),
92*5ffd83dbSDimitry Andric                   isExpandedFromMacro(getAssertMacro(Cmp)),
93*5ffd83dbSDimitry Andric                   hasArgument(2, Left), hasArgument(3, Right));
94*5ffd83dbSDimitry Andric }
95*5ffd83dbSDimitry Andric 
96*5ffd83dbSDimitry Andric internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left,
97*5ffd83dbSDimitry Andric                                             StatementMatcher Right) {
98*5ffd83dbSDimitry Andric   return callExpr(callee(getComparisonDecl(Cmp)),
99*5ffd83dbSDimitry Andric                   isExpandedFromMacro(getExpectMacro(Cmp)),
100*5ffd83dbSDimitry Andric                   hasArgument(2, Left), hasArgument(3, Right));
101*5ffd83dbSDimitry Andric }
102*5ffd83dbSDimitry Andric 
103*5ffd83dbSDimitry Andric } // end namespace ast_matchers
104*5ffd83dbSDimitry Andric } // end namespace clang
105