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