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