xref: /llvm-project/clang/lib/ASTMatchers/GtestMatchers.cpp (revision ece5dd101c7e4dc2fd23428abd312f75fd3d3eaf)
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