xref: /freebsd-src/contrib/llvm-project/clang/lib/ASTMatchers/GtestMatchers.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===- GtestMatchers.cpp - AST Matchers for Gtest ---------------*- C++ -*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric //
9*fe6060f1SDimitry Andric // This file implements several matchers for popular gtest macros. In general,
10*fe6060f1SDimitry Andric // AST matchers cannot match calls to macros. However, we can simulate such
11*fe6060f1SDimitry Andric // matches if the macro definition has identifiable elements that themselves can
12*fe6060f1SDimitry Andric // be matched. In that case, we can match on those elements and then check that
13*fe6060f1SDimitry Andric // the match occurs within an expansion of the desired macro. The more uncommon
14*fe6060f1SDimitry Andric // the identified elements, the more efficient this process will be.
15*fe6060f1SDimitry Andric //
16*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
175ffd83dbSDimitry Andric 
185ffd83dbSDimitry Andric #include "clang/ASTMatchers/GtestMatchers.h"
195ffd83dbSDimitry Andric #include "clang/AST/ASTConsumer.h"
205ffd83dbSDimitry Andric #include "clang/AST/ASTContext.h"
215ffd83dbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
22*fe6060f1SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
235ffd83dbSDimitry Andric #include "llvm/ADT/DenseMap.h"
24*fe6060f1SDimitry Andric #include "llvm/ADT/StringRef.h"
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric namespace clang {
275ffd83dbSDimitry Andric namespace ast_matchers {
28*fe6060f1SDimitry Andric namespace {
29*fe6060f1SDimitry Andric 
30*fe6060f1SDimitry Andric enum class MacroType {
31*fe6060f1SDimitry Andric   Expect,
32*fe6060f1SDimitry Andric   Assert,
33*fe6060f1SDimitry Andric   On,
34*fe6060f1SDimitry Andric };
35*fe6060f1SDimitry Andric 
36*fe6060f1SDimitry Andric } // namespace
375ffd83dbSDimitry Andric 
getComparisonDecl(GtestCmp Cmp)385ffd83dbSDimitry Andric static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) {
395ffd83dbSDimitry Andric   switch (Cmp) {
405ffd83dbSDimitry Andric   case GtestCmp::Eq:
415ffd83dbSDimitry Andric     return cxxMethodDecl(hasName("Compare"),
425ffd83dbSDimitry Andric                          ofClass(cxxRecordDecl(isSameOrDerivedFrom(
435ffd83dbSDimitry Andric                              hasName("::testing::internal::EqHelper")))));
445ffd83dbSDimitry Andric   case GtestCmp::Ne:
455ffd83dbSDimitry Andric     return functionDecl(hasName("::testing::internal::CmpHelperNE"));
465ffd83dbSDimitry Andric   case GtestCmp::Ge:
475ffd83dbSDimitry Andric     return functionDecl(hasName("::testing::internal::CmpHelperGE"));
485ffd83dbSDimitry Andric   case GtestCmp::Gt:
495ffd83dbSDimitry Andric     return functionDecl(hasName("::testing::internal::CmpHelperGT"));
505ffd83dbSDimitry Andric   case GtestCmp::Le:
515ffd83dbSDimitry Andric     return functionDecl(hasName("::testing::internal::CmpHelperLE"));
525ffd83dbSDimitry Andric   case GtestCmp::Lt:
535ffd83dbSDimitry Andric     return functionDecl(hasName("::testing::internal::CmpHelperLT"));
545ffd83dbSDimitry Andric   }
555ffd83dbSDimitry Andric   llvm_unreachable("Unhandled GtestCmp enum");
565ffd83dbSDimitry Andric }
575ffd83dbSDimitry Andric 
getMacroTypeName(MacroType Macro)58*fe6060f1SDimitry Andric static llvm::StringRef getMacroTypeName(MacroType Macro) {
59*fe6060f1SDimitry Andric   switch (Macro) {
60*fe6060f1SDimitry Andric   case MacroType::Expect:
61*fe6060f1SDimitry Andric     return "EXPECT";
62*fe6060f1SDimitry Andric   case MacroType::Assert:
63*fe6060f1SDimitry Andric     return "ASSERT";
64*fe6060f1SDimitry Andric   case MacroType::On:
65*fe6060f1SDimitry Andric     return "ON";
66*fe6060f1SDimitry Andric   }
67*fe6060f1SDimitry Andric   llvm_unreachable("Unhandled MacroType enum");
68*fe6060f1SDimitry Andric }
69*fe6060f1SDimitry Andric 
getComparisonTypeName(GtestCmp Cmp)70*fe6060f1SDimitry Andric static llvm::StringRef getComparisonTypeName(GtestCmp Cmp) {
715ffd83dbSDimitry Andric   switch (Cmp) {
725ffd83dbSDimitry Andric   case GtestCmp::Eq:
73*fe6060f1SDimitry Andric     return "EQ";
745ffd83dbSDimitry Andric   case GtestCmp::Ne:
75*fe6060f1SDimitry Andric     return "NE";
765ffd83dbSDimitry Andric   case GtestCmp::Ge:
77*fe6060f1SDimitry Andric     return "GE";
785ffd83dbSDimitry Andric   case GtestCmp::Gt:
79*fe6060f1SDimitry Andric     return "GT";
805ffd83dbSDimitry Andric   case GtestCmp::Le:
81*fe6060f1SDimitry Andric     return "LE";
825ffd83dbSDimitry Andric   case GtestCmp::Lt:
83*fe6060f1SDimitry Andric     return "LT";
845ffd83dbSDimitry Andric   }
855ffd83dbSDimitry Andric   llvm_unreachable("Unhandled GtestCmp enum");
865ffd83dbSDimitry Andric }
875ffd83dbSDimitry Andric 
getMacroName(MacroType Macro,GtestCmp Cmp)88*fe6060f1SDimitry Andric static std::string getMacroName(MacroType Macro, GtestCmp Cmp) {
89*fe6060f1SDimitry Andric   return (getMacroTypeName(Macro) + "_" + getComparisonTypeName(Cmp)).str();
905ffd83dbSDimitry Andric }
91*fe6060f1SDimitry Andric 
getMacroName(MacroType Macro,llvm::StringRef Operation)92*fe6060f1SDimitry Andric static std::string getMacroName(MacroType Macro, llvm::StringRef Operation) {
93*fe6060f1SDimitry Andric   return (getMacroTypeName(Macro) + "_" + Operation).str();
94*fe6060f1SDimitry Andric }
95*fe6060f1SDimitry Andric 
96*fe6060f1SDimitry Andric // Under the hood, ON_CALL is expanded to a call to `InternalDefaultActionSetAt`
97*fe6060f1SDimitry Andric // to set a default action spec to the underlying function mocker, while
98*fe6060f1SDimitry Andric // EXPECT_CALL is expanded to a call to `InternalExpectedAt` to set a new
99*fe6060f1SDimitry Andric // expectation spec.
getSpecSetterName(MacroType Macro)100*fe6060f1SDimitry Andric static llvm::StringRef getSpecSetterName(MacroType Macro) {
101*fe6060f1SDimitry Andric   switch (Macro) {
102*fe6060f1SDimitry Andric   case MacroType::On:
103*fe6060f1SDimitry Andric     return "InternalDefaultActionSetAt";
104*fe6060f1SDimitry Andric   case MacroType::Expect:
105*fe6060f1SDimitry Andric     return "InternalExpectedAt";
106*fe6060f1SDimitry Andric   default:
107*fe6060f1SDimitry Andric     llvm_unreachable("Unhandled MacroType enum");
108*fe6060f1SDimitry Andric   }
109*fe6060f1SDimitry Andric   llvm_unreachable("Unhandled MacroType enum");
1105ffd83dbSDimitry Andric }
1115ffd83dbSDimitry Andric 
1125ffd83dbSDimitry Andric // In general, AST matchers cannot match calls to macros. However, we can
1135ffd83dbSDimitry Andric // simulate such matches if the macro definition has identifiable elements that
1145ffd83dbSDimitry Andric // themselves can be matched. In that case, we can match on those elements and
1155ffd83dbSDimitry Andric // then check that the match occurs within an expansion of the desired
1165ffd83dbSDimitry Andric // macro. The more uncommon the identified elements, the more efficient this
1175ffd83dbSDimitry Andric // process will be.
1185ffd83dbSDimitry Andric //
1195ffd83dbSDimitry Andric // We use this approach to implement the derived matchers gtestAssert and
1205ffd83dbSDimitry Andric // gtestExpect.
121*fe6060f1SDimitry Andric static internal::BindableMatcher<Stmt>
gtestComparisonInternal(MacroType Macro,GtestCmp Cmp,StatementMatcher Left,StatementMatcher Right)122*fe6060f1SDimitry Andric gtestComparisonInternal(MacroType Macro, GtestCmp Cmp, StatementMatcher Left,
123*fe6060f1SDimitry Andric                         StatementMatcher Right) {
124*fe6060f1SDimitry Andric   return callExpr(isExpandedFromMacro(getMacroName(Macro, Cmp)),
125*fe6060f1SDimitry Andric                   callee(getComparisonDecl(Cmp)), hasArgument(2, Left),
126*fe6060f1SDimitry Andric                   hasArgument(3, Right));
127*fe6060f1SDimitry Andric }
128*fe6060f1SDimitry Andric 
129*fe6060f1SDimitry Andric static internal::BindableMatcher<Stmt>
gtestThatInternal(MacroType Macro,StatementMatcher Actual,StatementMatcher Matcher)130*fe6060f1SDimitry Andric gtestThatInternal(MacroType Macro, StatementMatcher Actual,
131*fe6060f1SDimitry Andric                   StatementMatcher Matcher) {
132*fe6060f1SDimitry Andric   return cxxOperatorCallExpr(
133*fe6060f1SDimitry Andric       isExpandedFromMacro(getMacroName(Macro, "THAT")),
134*fe6060f1SDimitry Andric       hasOverloadedOperatorName("()"), hasArgument(2, Actual),
135*fe6060f1SDimitry Andric       hasArgument(
136*fe6060f1SDimitry Andric           0, expr(hasType(classTemplateSpecializationDecl(hasName(
137*fe6060f1SDimitry Andric                       "::testing::internal::PredicateFormatterFromMatcher"))),
138*fe6060f1SDimitry Andric                   ignoringImplicit(
139*fe6060f1SDimitry Andric                       callExpr(callee(functionDecl(hasName(
140*fe6060f1SDimitry Andric                                    "::testing::internal::"
141*fe6060f1SDimitry Andric                                    "MakePredicateFormatterFromMatcher"))),
142*fe6060f1SDimitry Andric                                hasArgument(0, ignoringImplicit(Matcher)))))));
143*fe6060f1SDimitry Andric }
144*fe6060f1SDimitry Andric 
145*fe6060f1SDimitry Andric static internal::BindableMatcher<Stmt>
gtestCallInternal(MacroType Macro,StatementMatcher MockCall,MockArgs Args)146*fe6060f1SDimitry Andric gtestCallInternal(MacroType Macro, StatementMatcher MockCall, MockArgs Args) {
147*fe6060f1SDimitry Andric   // A ON_CALL or EXPECT_CALL macro expands to different AST structures
148*fe6060f1SDimitry Andric   // depending on whether the mock method has arguments or not.
149*fe6060f1SDimitry Andric   switch (Args) {
150*fe6060f1SDimitry Andric   // For example,
151*fe6060f1SDimitry Andric   // `ON_CALL(mock, TwoParamMethod)` is expanded to
152*fe6060f1SDimitry Andric   // `mock.gmock_TwoArgsMethod(WithoutMatchers(),
153*fe6060f1SDimitry Andric   // nullptr).InternalDefaultActionSetAt(...)`.
154*fe6060f1SDimitry Andric   // EXPECT_CALL is the same except
155*fe6060f1SDimitry Andric   // that it calls `InternalExpectedAt` instead of `InternalDefaultActionSetAt`
156*fe6060f1SDimitry Andric   // in the end.
157*fe6060f1SDimitry Andric   case MockArgs::None:
158*fe6060f1SDimitry Andric     return cxxMemberCallExpr(
159*fe6060f1SDimitry Andric         isExpandedFromMacro(getMacroName(Macro, "CALL")),
160*fe6060f1SDimitry Andric         callee(functionDecl(hasName(getSpecSetterName(Macro)))),
161*fe6060f1SDimitry Andric         onImplicitObjectArgument(ignoringImplicit(MockCall)));
162*fe6060f1SDimitry Andric   // For example,
163*fe6060f1SDimitry Andric   // `ON_CALL(mock, TwoParamMethod(m1, m2))` is expanded to
164*fe6060f1SDimitry Andric   // `mock.gmock_TwoParamMethod(m1,m2)(WithoutMatchers(),
165*fe6060f1SDimitry Andric   // nullptr).InternalDefaultActionSetAt(...)`.
166*fe6060f1SDimitry Andric   // EXPECT_CALL is the same except that it calls `InternalExpectedAt` instead
167*fe6060f1SDimitry Andric   // of `InternalDefaultActionSetAt` in the end.
168*fe6060f1SDimitry Andric   case MockArgs::Some:
169*fe6060f1SDimitry Andric     return cxxMemberCallExpr(
170*fe6060f1SDimitry Andric         isExpandedFromMacro(getMacroName(Macro, "CALL")),
171*fe6060f1SDimitry Andric         callee(functionDecl(hasName(getSpecSetterName(Macro)))),
172*fe6060f1SDimitry Andric         onImplicitObjectArgument(ignoringImplicit(cxxOperatorCallExpr(
173*fe6060f1SDimitry Andric             hasOverloadedOperatorName("()"), argumentCountIs(3),
174*fe6060f1SDimitry Andric             hasArgument(0, ignoringImplicit(MockCall))))));
175*fe6060f1SDimitry Andric   }
176*fe6060f1SDimitry Andric   llvm_unreachable("Unhandled MockArgs enum");
177*fe6060f1SDimitry Andric }
178*fe6060f1SDimitry Andric 
179*fe6060f1SDimitry Andric static internal::BindableMatcher<Stmt>
gtestCallInternal(MacroType Macro,StatementMatcher MockObject,llvm::StringRef MockMethodName,MockArgs Args)180*fe6060f1SDimitry Andric gtestCallInternal(MacroType Macro, StatementMatcher MockObject,
181*fe6060f1SDimitry Andric                   llvm::StringRef MockMethodName, MockArgs Args) {
182*fe6060f1SDimitry Andric   return gtestCallInternal(
183*fe6060f1SDimitry Andric       Macro,
184*fe6060f1SDimitry Andric       cxxMemberCallExpr(
185*fe6060f1SDimitry Andric           onImplicitObjectArgument(MockObject),
186*fe6060f1SDimitry Andric           callee(functionDecl(hasName(("gmock_" + MockMethodName).str())))),
187*fe6060f1SDimitry Andric       Args);
188*fe6060f1SDimitry Andric }
189*fe6060f1SDimitry Andric 
gtestAssert(GtestCmp Cmp,StatementMatcher Left,StatementMatcher Right)1905ffd83dbSDimitry Andric internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left,
1915ffd83dbSDimitry Andric                                             StatementMatcher Right) {
192*fe6060f1SDimitry Andric   return gtestComparisonInternal(MacroType::Assert, Cmp, Left, Right);
1935ffd83dbSDimitry Andric }
1945ffd83dbSDimitry Andric 
gtestExpect(GtestCmp Cmp,StatementMatcher Left,StatementMatcher Right)1955ffd83dbSDimitry Andric internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left,
1965ffd83dbSDimitry Andric                                             StatementMatcher Right) {
197*fe6060f1SDimitry Andric   return gtestComparisonInternal(MacroType::Expect, Cmp, Left, Right);
198*fe6060f1SDimitry Andric }
199*fe6060f1SDimitry Andric 
gtestAssertThat(StatementMatcher Actual,StatementMatcher Matcher)200*fe6060f1SDimitry Andric internal::BindableMatcher<Stmt> gtestAssertThat(StatementMatcher Actual,
201*fe6060f1SDimitry Andric                                                 StatementMatcher Matcher) {
202*fe6060f1SDimitry Andric   return gtestThatInternal(MacroType::Assert, Actual, Matcher);
203*fe6060f1SDimitry Andric }
204*fe6060f1SDimitry Andric 
gtestExpectThat(StatementMatcher Actual,StatementMatcher Matcher)205*fe6060f1SDimitry Andric internal::BindableMatcher<Stmt> gtestExpectThat(StatementMatcher Actual,
206*fe6060f1SDimitry Andric                                                 StatementMatcher Matcher) {
207*fe6060f1SDimitry Andric   return gtestThatInternal(MacroType::Expect, Actual, Matcher);
208*fe6060f1SDimitry Andric }
209*fe6060f1SDimitry Andric 
gtestOnCall(StatementMatcher MockObject,llvm::StringRef MockMethodName,MockArgs Args)210*fe6060f1SDimitry Andric internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockObject,
211*fe6060f1SDimitry Andric                                             llvm::StringRef MockMethodName,
212*fe6060f1SDimitry Andric                                             MockArgs Args) {
213*fe6060f1SDimitry Andric   return gtestCallInternal(MacroType::On, MockObject, MockMethodName, Args);
214*fe6060f1SDimitry Andric }
215*fe6060f1SDimitry Andric 
gtestOnCall(StatementMatcher MockCall,MockArgs Args)216*fe6060f1SDimitry Andric internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockCall,
217*fe6060f1SDimitry Andric                                             MockArgs Args) {
218*fe6060f1SDimitry Andric   return gtestCallInternal(MacroType::On, MockCall, Args);
219*fe6060f1SDimitry Andric }
220*fe6060f1SDimitry Andric 
gtestExpectCall(StatementMatcher MockObject,llvm::StringRef MockMethodName,MockArgs Args)221*fe6060f1SDimitry Andric internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockObject,
222*fe6060f1SDimitry Andric                                                 llvm::StringRef MockMethodName,
223*fe6060f1SDimitry Andric                                                 MockArgs Args) {
224*fe6060f1SDimitry Andric   return gtestCallInternal(MacroType::Expect, MockObject, MockMethodName, Args);
225*fe6060f1SDimitry Andric }
226*fe6060f1SDimitry Andric 
gtestExpectCall(StatementMatcher MockCall,MockArgs Args)227*fe6060f1SDimitry Andric internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockCall,
228*fe6060f1SDimitry Andric                                                 MockArgs Args) {
229*fe6060f1SDimitry Andric   return gtestCallInternal(MacroType::Expect, MockCall, Args);
2305ffd83dbSDimitry Andric }
2315ffd83dbSDimitry Andric 
2325ffd83dbSDimitry Andric } // end namespace ast_matchers
2335ffd83dbSDimitry Andric } // end namespace clang
234