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