123444edfSYitzhak Mandelbaum //===- GtestMatchers.cpp - AST Matchers for Gtest ---------------*- C++ -*-===//
223444edfSYitzhak Mandelbaum //
323444edfSYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
423444edfSYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information.
523444edfSYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
623444edfSYitzhak Mandelbaum //
723444edfSYitzhak Mandelbaum //===----------------------------------------------------------------------===//
8d0e15933SZhaomo Yang //
9d0e15933SZhaomo Yang // This file implements several matchers for popular gtest macros. In general,
10d0e15933SZhaomo Yang // AST matchers cannot match calls to macros. However, we can simulate such
11d0e15933SZhaomo Yang // matches if the macro definition has identifiable elements that themselves can
12d0e15933SZhaomo Yang // be matched. In that case, we can match on those elements and then check that
13d0e15933SZhaomo Yang // the match occurs within an expansion of the desired macro. The more uncommon
14d0e15933SZhaomo Yang // the identified elements, the more efficient this process will be.
15d0e15933SZhaomo Yang //
16d0e15933SZhaomo Yang //===----------------------------------------------------------------------===//
1723444edfSYitzhak Mandelbaum
1823444edfSYitzhak Mandelbaum #include "clang/ASTMatchers/GtestMatchers.h"
1923444edfSYitzhak Mandelbaum #include "clang/AST/ASTConsumer.h"
2023444edfSYitzhak Mandelbaum #include "clang/AST/ASTContext.h"
2123444edfSYitzhak Mandelbaum #include "clang/AST/RecursiveASTVisitor.h"
22d0e15933SZhaomo Yang #include "clang/ASTMatchers/ASTMatchFinder.h"
2323444edfSYitzhak Mandelbaum #include "llvm/ADT/DenseMap.h"
24d0e15933SZhaomo Yang #include "llvm/ADT/StringRef.h"
2523444edfSYitzhak Mandelbaum
2623444edfSYitzhak Mandelbaum namespace clang {
2723444edfSYitzhak Mandelbaum namespace ast_matchers {
28d0e15933SZhaomo Yang namespace {
29d0e15933SZhaomo Yang
30d0e15933SZhaomo Yang enum class MacroType {
31d0e15933SZhaomo Yang Expect,
32d0e15933SZhaomo Yang Assert,
33d0e15933SZhaomo Yang On,
34d0e15933SZhaomo Yang };
35d0e15933SZhaomo Yang
36d0e15933SZhaomo Yang } // namespace
3723444edfSYitzhak Mandelbaum
getComparisonDecl(GtestCmp Cmp)3823444edfSYitzhak Mandelbaum static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) {
3923444edfSYitzhak Mandelbaum switch (Cmp) {
4023444edfSYitzhak Mandelbaum case GtestCmp::Eq:
4123444edfSYitzhak Mandelbaum return cxxMethodDecl(hasName("Compare"),
4223444edfSYitzhak Mandelbaum ofClass(cxxRecordDecl(isSameOrDerivedFrom(
4323444edfSYitzhak Mandelbaum hasName("::testing::internal::EqHelper")))));
4423444edfSYitzhak Mandelbaum case GtestCmp::Ne:
4523444edfSYitzhak Mandelbaum return functionDecl(hasName("::testing::internal::CmpHelperNE"));
4623444edfSYitzhak Mandelbaum case GtestCmp::Ge:
4723444edfSYitzhak Mandelbaum return functionDecl(hasName("::testing::internal::CmpHelperGE"));
4823444edfSYitzhak Mandelbaum case GtestCmp::Gt:
4923444edfSYitzhak Mandelbaum return functionDecl(hasName("::testing::internal::CmpHelperGT"));
5023444edfSYitzhak Mandelbaum case GtestCmp::Le:
5123444edfSYitzhak Mandelbaum return functionDecl(hasName("::testing::internal::CmpHelperLE"));
5223444edfSYitzhak Mandelbaum case GtestCmp::Lt:
5323444edfSYitzhak Mandelbaum return functionDecl(hasName("::testing::internal::CmpHelperLT"));
5423444edfSYitzhak Mandelbaum }
55*b2c8bcbaSZhaomo Yang llvm_unreachable("Unhandled GtestCmp enum");
5623444edfSYitzhak Mandelbaum }
5723444edfSYitzhak Mandelbaum
getMacroTypeName(MacroType Macro)58d0e15933SZhaomo Yang static llvm::StringRef getMacroTypeName(MacroType Macro) {
59d0e15933SZhaomo Yang switch (Macro) {
60d0e15933SZhaomo Yang case MacroType::Expect:
61d0e15933SZhaomo Yang return "EXPECT";
62d0e15933SZhaomo Yang case MacroType::Assert:
63d0e15933SZhaomo Yang return "ASSERT";
64d0e15933SZhaomo Yang case MacroType::On:
65d0e15933SZhaomo Yang return "ON";
6623444edfSYitzhak Mandelbaum }
67*b2c8bcbaSZhaomo Yang llvm_unreachable("Unhandled MacroType enum");
6823444edfSYitzhak Mandelbaum }
6923444edfSYitzhak Mandelbaum
getComparisonTypeName(GtestCmp Cmp)70d0e15933SZhaomo Yang static llvm::StringRef getComparisonTypeName(GtestCmp Cmp) {
7123444edfSYitzhak Mandelbaum switch (Cmp) {
7223444edfSYitzhak Mandelbaum case GtestCmp::Eq:
73d0e15933SZhaomo Yang return "EQ";
7423444edfSYitzhak Mandelbaum case GtestCmp::Ne:
75d0e15933SZhaomo Yang return "NE";
7623444edfSYitzhak Mandelbaum case GtestCmp::Ge:
77d0e15933SZhaomo Yang return "GE";
7823444edfSYitzhak Mandelbaum case GtestCmp::Gt:
79d0e15933SZhaomo Yang return "GT";
8023444edfSYitzhak Mandelbaum case GtestCmp::Le:
81d0e15933SZhaomo Yang return "LE";
8223444edfSYitzhak Mandelbaum case GtestCmp::Lt:
83d0e15933SZhaomo Yang return "LT";
8423444edfSYitzhak Mandelbaum }
85*b2c8bcbaSZhaomo Yang llvm_unreachable("Unhandled GtestCmp enum");
86d0e15933SZhaomo Yang }
87d0e15933SZhaomo Yang
getMacroName(MacroType Macro,GtestCmp Cmp)88d0e15933SZhaomo Yang static std::string getMacroName(MacroType Macro, GtestCmp Cmp) {
89d0e15933SZhaomo Yang return (getMacroTypeName(Macro) + "_" + getComparisonTypeName(Cmp)).str();
90d0e15933SZhaomo Yang }
91d0e15933SZhaomo Yang
getMacroName(MacroType Macro,llvm::StringRef Operation)92d0e15933SZhaomo Yang static std::string getMacroName(MacroType Macro, llvm::StringRef Operation) {
93d0e15933SZhaomo Yang return (getMacroTypeName(Macro) + "_" + Operation).str();
94d0e15933SZhaomo Yang }
95d0e15933SZhaomo Yang
96d0e15933SZhaomo Yang // Under the hood, ON_CALL is expanded to a call to `InternalDefaultActionSetAt`
97d0e15933SZhaomo Yang // to set a default action spec to the underlying function mocker, while
98d0e15933SZhaomo Yang // EXPECT_CALL is expanded to a call to `InternalExpectedAt` to set a new
99d0e15933SZhaomo Yang // expectation spec.
getSpecSetterName(MacroType Macro)100d0e15933SZhaomo Yang static llvm::StringRef getSpecSetterName(MacroType Macro) {
101d0e15933SZhaomo Yang switch (Macro) {
102d0e15933SZhaomo Yang case MacroType::On:
103d0e15933SZhaomo Yang return "InternalDefaultActionSetAt";
104d0e15933SZhaomo Yang case MacroType::Expect:
105d0e15933SZhaomo Yang return "InternalExpectedAt";
106d0e15933SZhaomo Yang default:
107d0e15933SZhaomo Yang llvm_unreachable("Unhandled MacroType enum");
108d0e15933SZhaomo Yang }
109*b2c8bcbaSZhaomo Yang llvm_unreachable("Unhandled MacroType enum");
11023444edfSYitzhak Mandelbaum }
11123444edfSYitzhak Mandelbaum
11223444edfSYitzhak Mandelbaum // In general, AST matchers cannot match calls to macros. However, we can
11323444edfSYitzhak Mandelbaum // simulate such matches if the macro definition has identifiable elements that
11423444edfSYitzhak Mandelbaum // themselves can be matched. In that case, we can match on those elements and
11523444edfSYitzhak Mandelbaum // then check that the match occurs within an expansion of the desired
11623444edfSYitzhak Mandelbaum // macro. The more uncommon the identified elements, the more efficient this
11723444edfSYitzhak Mandelbaum // process will be.
11823444edfSYitzhak Mandelbaum //
11923444edfSYitzhak Mandelbaum // We use this approach to implement the derived matchers gtestAssert and
12023444edfSYitzhak Mandelbaum // gtestExpect.
121d0e15933SZhaomo Yang static internal::BindableMatcher<Stmt>
gtestComparisonInternal(MacroType Macro,GtestCmp Cmp,StatementMatcher Left,StatementMatcher Right)122d0e15933SZhaomo Yang gtestComparisonInternal(MacroType Macro, GtestCmp Cmp, StatementMatcher Left,
123d0e15933SZhaomo Yang StatementMatcher Right) {
124d0e15933SZhaomo Yang return callExpr(isExpandedFromMacro(getMacroName(Macro, Cmp)),
125d0e15933SZhaomo Yang callee(getComparisonDecl(Cmp)), hasArgument(2, Left),
126d0e15933SZhaomo Yang hasArgument(3, Right));
127d0e15933SZhaomo Yang }
128d0e15933SZhaomo Yang
129d0e15933SZhaomo Yang static internal::BindableMatcher<Stmt>
gtestThatInternal(MacroType Macro,StatementMatcher Actual,StatementMatcher Matcher)130d0e15933SZhaomo Yang gtestThatInternal(MacroType Macro, StatementMatcher Actual,
131d0e15933SZhaomo Yang StatementMatcher Matcher) {
132d0e15933SZhaomo Yang return cxxOperatorCallExpr(
133d0e15933SZhaomo Yang isExpandedFromMacro(getMacroName(Macro, "THAT")),
134d0e15933SZhaomo Yang hasOverloadedOperatorName("()"), hasArgument(2, Actual),
135d0e15933SZhaomo Yang hasArgument(
136d0e15933SZhaomo Yang 0, expr(hasType(classTemplateSpecializationDecl(hasName(
137d0e15933SZhaomo Yang "::testing::internal::PredicateFormatterFromMatcher"))),
138d0e15933SZhaomo Yang ignoringImplicit(
139d0e15933SZhaomo Yang callExpr(callee(functionDecl(hasName(
140d0e15933SZhaomo Yang "::testing::internal::"
141d0e15933SZhaomo Yang "MakePredicateFormatterFromMatcher"))),
142d0e15933SZhaomo Yang hasArgument(0, ignoringImplicit(Matcher)))))));
143d0e15933SZhaomo Yang }
144d0e15933SZhaomo Yang
145d0e15933SZhaomo Yang static internal::BindableMatcher<Stmt>
gtestCallInternal(MacroType Macro,StatementMatcher MockCall,MockArgs Args)146d0e15933SZhaomo Yang gtestCallInternal(MacroType Macro, StatementMatcher MockCall, MockArgs Args) {
147d0e15933SZhaomo Yang // A ON_CALL or EXPECT_CALL macro expands to different AST structures
148d0e15933SZhaomo Yang // depending on whether the mock method has arguments or not.
149d0e15933SZhaomo Yang switch (Args) {
150d0e15933SZhaomo Yang // For example,
151d0e15933SZhaomo Yang // `ON_CALL(mock, TwoParamMethod)` is expanded to
152d0e15933SZhaomo Yang // `mock.gmock_TwoArgsMethod(WithoutMatchers(),
153d0e15933SZhaomo Yang // nullptr).InternalDefaultActionSetAt(...)`.
154d0e15933SZhaomo Yang // EXPECT_CALL is the same except
155d0e15933SZhaomo Yang // that it calls `InternalExpectedAt` instead of `InternalDefaultActionSetAt`
156d0e15933SZhaomo Yang // in the end.
157d0e15933SZhaomo Yang case MockArgs::None:
158d0e15933SZhaomo Yang return cxxMemberCallExpr(
159d0e15933SZhaomo Yang isExpandedFromMacro(getMacroName(Macro, "CALL")),
160d0e15933SZhaomo Yang callee(functionDecl(hasName(getSpecSetterName(Macro)))),
161d0e15933SZhaomo Yang onImplicitObjectArgument(ignoringImplicit(MockCall)));
162d0e15933SZhaomo Yang // For example,
163d0e15933SZhaomo Yang // `ON_CALL(mock, TwoParamMethod(m1, m2))` is expanded to
164d0e15933SZhaomo Yang // `mock.gmock_TwoParamMethod(m1,m2)(WithoutMatchers(),
165d0e15933SZhaomo Yang // nullptr).InternalDefaultActionSetAt(...)`.
166d0e15933SZhaomo Yang // EXPECT_CALL is the same except that it calls `InternalExpectedAt` instead
167d0e15933SZhaomo Yang // of `InternalDefaultActionSetAt` in the end.
168d0e15933SZhaomo Yang case MockArgs::Some:
169d0e15933SZhaomo Yang return cxxMemberCallExpr(
170d0e15933SZhaomo Yang isExpandedFromMacro(getMacroName(Macro, "CALL")),
171d0e15933SZhaomo Yang callee(functionDecl(hasName(getSpecSetterName(Macro)))),
172d0e15933SZhaomo Yang onImplicitObjectArgument(ignoringImplicit(cxxOperatorCallExpr(
173d0e15933SZhaomo Yang hasOverloadedOperatorName("()"), argumentCountIs(3),
174d0e15933SZhaomo Yang hasArgument(0, ignoringImplicit(MockCall))))));
175d0e15933SZhaomo Yang }
176*b2c8bcbaSZhaomo Yang llvm_unreachable("Unhandled MockArgs enum");
177d0e15933SZhaomo Yang }
178d0e15933SZhaomo Yang
179d0e15933SZhaomo Yang static internal::BindableMatcher<Stmt>
gtestCallInternal(MacroType Macro,StatementMatcher MockObject,llvm::StringRef MockMethodName,MockArgs Args)180d0e15933SZhaomo Yang gtestCallInternal(MacroType Macro, StatementMatcher MockObject,
181d0e15933SZhaomo Yang llvm::StringRef MockMethodName, MockArgs Args) {
182d0e15933SZhaomo Yang return gtestCallInternal(
183d0e15933SZhaomo Yang Macro,
184d0e15933SZhaomo Yang cxxMemberCallExpr(
185d0e15933SZhaomo Yang onImplicitObjectArgument(MockObject),
186d0e15933SZhaomo Yang callee(functionDecl(hasName(("gmock_" + MockMethodName).str())))),
187d0e15933SZhaomo Yang Args);
188d0e15933SZhaomo Yang }
189d0e15933SZhaomo Yang
gtestAssert(GtestCmp Cmp,StatementMatcher Left,StatementMatcher Right)19023444edfSYitzhak Mandelbaum internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left,
19123444edfSYitzhak Mandelbaum StatementMatcher Right) {
192d0e15933SZhaomo Yang return gtestComparisonInternal(MacroType::Assert, Cmp, Left, Right);
19323444edfSYitzhak Mandelbaum }
19423444edfSYitzhak Mandelbaum
gtestExpect(GtestCmp Cmp,StatementMatcher Left,StatementMatcher Right)19523444edfSYitzhak Mandelbaum internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left,
19623444edfSYitzhak Mandelbaum StatementMatcher Right) {
197d0e15933SZhaomo Yang return gtestComparisonInternal(MacroType::Expect, Cmp, Left, Right);
198d0e15933SZhaomo Yang }
199d0e15933SZhaomo Yang
gtestAssertThat(StatementMatcher Actual,StatementMatcher Matcher)200d0e15933SZhaomo Yang internal::BindableMatcher<Stmt> gtestAssertThat(StatementMatcher Actual,
201d0e15933SZhaomo Yang StatementMatcher Matcher) {
202d0e15933SZhaomo Yang return gtestThatInternal(MacroType::Assert, Actual, Matcher);
203d0e15933SZhaomo Yang }
204d0e15933SZhaomo Yang
gtestExpectThat(StatementMatcher Actual,StatementMatcher Matcher)205d0e15933SZhaomo Yang internal::BindableMatcher<Stmt> gtestExpectThat(StatementMatcher Actual,
206d0e15933SZhaomo Yang StatementMatcher Matcher) {
207d0e15933SZhaomo Yang return gtestThatInternal(MacroType::Expect, Actual, Matcher);
208d0e15933SZhaomo Yang }
209d0e15933SZhaomo Yang
gtestOnCall(StatementMatcher MockObject,llvm::StringRef MockMethodName,MockArgs Args)210d0e15933SZhaomo Yang internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockObject,
211d0e15933SZhaomo Yang llvm::StringRef MockMethodName,
212d0e15933SZhaomo Yang MockArgs Args) {
213d0e15933SZhaomo Yang return gtestCallInternal(MacroType::On, MockObject, MockMethodName, Args);
214d0e15933SZhaomo Yang }
215d0e15933SZhaomo Yang
gtestOnCall(StatementMatcher MockCall,MockArgs Args)216d0e15933SZhaomo Yang internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockCall,
217d0e15933SZhaomo Yang MockArgs Args) {
218d0e15933SZhaomo Yang return gtestCallInternal(MacroType::On, MockCall, Args);
219d0e15933SZhaomo Yang }
220d0e15933SZhaomo Yang
gtestExpectCall(StatementMatcher MockObject,llvm::StringRef MockMethodName,MockArgs Args)221d0e15933SZhaomo Yang internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockObject,
222d0e15933SZhaomo Yang llvm::StringRef MockMethodName,
223d0e15933SZhaomo Yang MockArgs Args) {
224d0e15933SZhaomo Yang return gtestCallInternal(MacroType::Expect, MockObject, MockMethodName, Args);
225d0e15933SZhaomo Yang }
226d0e15933SZhaomo Yang
gtestExpectCall(StatementMatcher MockCall,MockArgs Args)227d0e15933SZhaomo Yang internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockCall,
228d0e15933SZhaomo Yang MockArgs Args) {
229d0e15933SZhaomo Yang return gtestCallInternal(MacroType::Expect, MockCall, Args);
23023444edfSYitzhak Mandelbaum }
23123444edfSYitzhak Mandelbaum
23223444edfSYitzhak Mandelbaum } // end namespace ast_matchers
23323444edfSYitzhak Mandelbaum } // end namespace clang
234