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