/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/ASTMatchers/GtestMatchers.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | // This file implements several matchers for popular gtest macros. In general, |
10 | | // AST matchers cannot match calls to macros. However, we can simulate such |
11 | | // matches if the macro definition has identifiable elements that themselves can |
12 | | // be matched. In that case, we can match on those elements and then check that |
13 | | // the match occurs within an expansion of the desired macro. The more uncommon |
14 | | // the identified elements, the more efficient this process will be. |
15 | | // |
16 | | //===----------------------------------------------------------------------===// |
17 | | |
18 | | #include "clang/ASTMatchers/GtestMatchers.h" |
19 | | #include "clang/AST/ASTConsumer.h" |
20 | | #include "clang/AST/ASTContext.h" |
21 | | #include "clang/AST/RecursiveASTVisitor.h" |
22 | | #include "clang/ASTMatchers/ASTMatchFinder.h" |
23 | | #include "llvm/ADT/DenseMap.h" |
24 | | #include "llvm/ADT/StringMap.h" |
25 | | #include "llvm/ADT/StringRef.h" |
26 | | |
27 | | namespace clang { |
28 | | namespace ast_matchers { |
29 | | namespace { |
30 | | |
31 | | enum class MacroType { |
32 | | Expect, |
33 | | Assert, |
34 | | On, |
35 | | }; |
36 | | |
37 | | } // namespace |
38 | | |
39 | 10 | static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) { |
40 | 10 | switch (Cmp) { |
41 | 5 | case GtestCmp::Eq: |
42 | 5 | return cxxMethodDecl(hasName("Compare"), |
43 | 5 | ofClass(cxxRecordDecl(isSameOrDerivedFrom( |
44 | 5 | hasName("::testing::internal::EqHelper"))))); |
45 | 1 | case GtestCmp::Ne: |
46 | 1 | return functionDecl(hasName("::testing::internal::CmpHelperNE")); |
47 | 1 | case GtestCmp::Ge: |
48 | 1 | return functionDecl(hasName("::testing::internal::CmpHelperGE")); |
49 | 1 | case GtestCmp::Gt: |
50 | 1 | return functionDecl(hasName("::testing::internal::CmpHelperGT")); |
51 | 1 | case GtestCmp::Le: |
52 | 1 | return functionDecl(hasName("::testing::internal::CmpHelperLE")); |
53 | 1 | case GtestCmp::Lt: |
54 | 1 | return functionDecl(hasName("::testing::internal::CmpHelperLT")); |
55 | 10 | } |
56 | 0 | llvm_unreachable("Unhandled GtestCmp enum"); |
57 | 0 | } |
58 | | |
59 | 20 | static llvm::StringRef getMacroTypeName(MacroType Macro) { |
60 | 20 | switch (Macro) { |
61 | 12 | case MacroType::Expect: |
62 | 12 | return "EXPECT"; |
63 | 4 | case MacroType::Assert: |
64 | 4 | return "ASSERT"; |
65 | 4 | case MacroType::On: |
66 | 4 | return "ON"; |
67 | 20 | } |
68 | 0 | llvm_unreachable("Unhandled MacroType enum"); |
69 | 0 | } |
70 | | |
71 | 10 | static llvm::StringRef getComparisonTypeName(GtestCmp Cmp) { |
72 | 10 | switch (Cmp) { |
73 | 5 | case GtestCmp::Eq: |
74 | 5 | return "EQ"; |
75 | 1 | case GtestCmp::Ne: |
76 | 1 | return "NE"; |
77 | 1 | case GtestCmp::Ge: |
78 | 1 | return "GE"; |
79 | 1 | case GtestCmp::Gt: |
80 | 1 | return "GT"; |
81 | 1 | case GtestCmp::Le: |
82 | 1 | return "LE"; |
83 | 1 | case GtestCmp::Lt: |
84 | 1 | return "LT"; |
85 | 10 | } |
86 | 0 | llvm_unreachable("Unhandled GtestCmp enum"); |
87 | 0 | } |
88 | | |
89 | 10 | static std::string getMacroName(MacroType Macro, GtestCmp Cmp) { |
90 | 10 | return (getMacroTypeName(Macro) + "_" + getComparisonTypeName(Cmp)).str(); |
91 | 10 | } |
92 | | |
93 | 10 | static std::string getMacroName(MacroType Macro, llvm::StringRef Operation) { |
94 | 10 | return (getMacroTypeName(Macro) + "_" + Operation).str(); |
95 | 10 | } |
96 | | |
97 | | // Under the hood, ON_CALL is expanded to a call to `InternalDefaultActionSetAt` |
98 | | // to set a default action spec to the underlying function mocker, while |
99 | | // EXPECT_CALL is expanded to a call to `InternalExpectedAt` to set a new |
100 | | // expectation spec. |
101 | 8 | static llvm::StringRef getSpecSetterName(MacroType Macro) { |
102 | 8 | switch (Macro) { |
103 | 4 | case MacroType::On: |
104 | 4 | return "InternalDefaultActionSetAt"; |
105 | 4 | case MacroType::Expect: |
106 | 4 | return "InternalExpectedAt"; |
107 | 0 | default: |
108 | 0 | llvm_unreachable("Unhandled MacroType enum"); |
109 | 8 | } |
110 | 0 | llvm_unreachable("Unhandled MacroType enum"); |
111 | 0 | } |
112 | | |
113 | | // In general, AST matchers cannot match calls to macros. However, we can |
114 | | // simulate such matches if the macro definition has identifiable elements that |
115 | | // themselves can be matched. In that case, we can match on those elements and |
116 | | // then check that the match occurs within an expansion of the desired |
117 | | // macro. The more uncommon the identified elements, the more efficient this |
118 | | // process will be. |
119 | | // |
120 | | // We use this approach to implement the derived matchers gtestAssert and |
121 | | // gtestExpect. |
122 | | static internal::BindableMatcher<Stmt> |
123 | | gtestComparisonInternal(MacroType Macro, GtestCmp Cmp, StatementMatcher Left, |
124 | 10 | StatementMatcher Right) { |
125 | 10 | return callExpr(isExpandedFromMacro(getMacroName(Macro, Cmp)), |
126 | 10 | callee(getComparisonDecl(Cmp)), hasArgument(2, Left), |
127 | 10 | hasArgument(3, Right)); |
128 | 10 | } |
129 | | |
130 | | static internal::BindableMatcher<Stmt> |
131 | | gtestThatInternal(MacroType Macro, StatementMatcher Actual, |
132 | 2 | StatementMatcher Matcher) { |
133 | 2 | return cxxOperatorCallExpr( |
134 | 2 | isExpandedFromMacro(getMacroName(Macro, "THAT")), |
135 | 2 | hasOverloadedOperatorName("()"), hasArgument(2, Actual), |
136 | 2 | hasArgument( |
137 | 2 | 0, expr(hasType(classTemplateSpecializationDecl(hasName( |
138 | 2 | "::testing::internal::PredicateFormatterFromMatcher"))), |
139 | 2 | ignoringImplicit( |
140 | 2 | callExpr(callee(functionDecl(hasName( |
141 | 2 | "::testing::internal::" |
142 | 2 | "MakePredicateFormatterFromMatcher"))), |
143 | 2 | hasArgument(0, ignoringImplicit(Matcher))))))); |
144 | 2 | } |
145 | | |
146 | | static internal::BindableMatcher<Stmt> |
147 | 8 | gtestCallInternal(MacroType Macro, StatementMatcher MockCall, MockArgs Args) { |
148 | | // A ON_CALL or EXPECT_CALL macro expands to different AST structures |
149 | | // depending on whether the mock method has arguments or not. |
150 | 8 | switch (Args) { |
151 | | // For example, |
152 | | // `ON_CALL(mock, TwoParamMethod)` is expanded to |
153 | | // `mock.gmock_TwoArgsMethod(WithoutMatchers(), |
154 | | // nullptr).InternalDefaultActionSetAt(...)`. |
155 | | // EXPECT_CALL is the same except |
156 | | // that it calls `InternalExpectedAt` instead of `InternalDefaultActionSetAt` |
157 | | // in the end. |
158 | 4 | case MockArgs::None: |
159 | 4 | return cxxMemberCallExpr( |
160 | 4 | isExpandedFromMacro(getMacroName(Macro, "CALL")), |
161 | 4 | callee(functionDecl(hasName(getSpecSetterName(Macro)))), |
162 | 4 | onImplicitObjectArgument(ignoringImplicit(MockCall))); |
163 | | // For example, |
164 | | // `ON_CALL(mock, TwoParamMethod(m1, m2))` is expanded to |
165 | | // `mock.gmock_TwoParamMethod(m1,m2)(WithoutMatchers(), |
166 | | // nullptr).InternalDefaultActionSetAt(...)`. |
167 | | // EXPECT_CALL is the same except that it calls `InternalExpectedAt` instead |
168 | | // of `InternalDefaultActionSetAt` in the end. |
169 | 4 | case MockArgs::Some: |
170 | 4 | return cxxMemberCallExpr( |
171 | 4 | isExpandedFromMacro(getMacroName(Macro, "CALL")), |
172 | 4 | callee(functionDecl(hasName(getSpecSetterName(Macro)))), |
173 | 4 | onImplicitObjectArgument(ignoringImplicit(cxxOperatorCallExpr( |
174 | 4 | hasOverloadedOperatorName("()"), argumentCountIs(3), |
175 | 4 | hasArgument(0, ignoringImplicit(MockCall)))))); |
176 | 8 | } |
177 | 0 | llvm_unreachable("Unhandled MockArgs enum"); |
178 | 0 | } |
179 | | |
180 | | static internal::BindableMatcher<Stmt> |
181 | | gtestCallInternal(MacroType Macro, StatementMatcher MockObject, |
182 | 4 | llvm::StringRef MockMethodName, MockArgs Args) { |
183 | 4 | return gtestCallInternal( |
184 | 4 | Macro, |
185 | 4 | cxxMemberCallExpr( |
186 | 4 | onImplicitObjectArgument(MockObject), |
187 | 4 | callee(functionDecl(hasName(("gmock_" + MockMethodName).str())))), |
188 | 4 | Args); |
189 | 4 | } |
190 | | |
191 | | internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left, |
192 | 3 | StatementMatcher Right) { |
193 | 3 | return gtestComparisonInternal(MacroType::Assert, Cmp, Left, Right); |
194 | 3 | } |
195 | | |
196 | | internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left, |
197 | 7 | StatementMatcher Right) { |
198 | 7 | return gtestComparisonInternal(MacroType::Expect, Cmp, Left, Right); |
199 | 7 | } |
200 | | |
201 | | internal::BindableMatcher<Stmt> gtestAssertThat(StatementMatcher Actual, |
202 | 1 | StatementMatcher Matcher) { |
203 | 1 | return gtestThatInternal(MacroType::Assert, Actual, Matcher); |
204 | 1 | } |
205 | | |
206 | | internal::BindableMatcher<Stmt> gtestExpectThat(StatementMatcher Actual, |
207 | 1 | StatementMatcher Matcher) { |
208 | 1 | return gtestThatInternal(MacroType::Expect, Actual, Matcher); |
209 | 1 | } |
210 | | |
211 | | internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockObject, |
212 | | llvm::StringRef MockMethodName, |
213 | 2 | MockArgs Args) { |
214 | 2 | return gtestCallInternal(MacroType::On, MockObject, MockMethodName, Args); |
215 | 2 | } |
216 | | |
217 | | internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockCall, |
218 | 2 | MockArgs Args) { |
219 | 2 | return gtestCallInternal(MacroType::On, MockCall, Args); |
220 | 2 | } |
221 | | |
222 | | internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockObject, |
223 | | llvm::StringRef MockMethodName, |
224 | 2 | MockArgs Args) { |
225 | 2 | return gtestCallInternal(MacroType::Expect, MockObject, MockMethodName, Args); |
226 | 2 | } |
227 | | |
228 | | internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockCall, |
229 | 2 | MockArgs Args) { |
230 | 2 | return gtestCallInternal(MacroType::Expect, MockCall, Args); |
231 | 2 | } |
232 | | |
233 | | } // end namespace ast_matchers |
234 | | } // end namespace clang |