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