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