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 #include "clang/ASTMatchers/GtestMatchers.h" 10 #include "clang/ASTMatchers/ASTMatchFinder.h" 11 #include "clang/AST/ASTConsumer.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/AST/RecursiveASTVisitor.h" 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/ADT/StringMap.h" 16 #include "llvm/Support/Timer.h" 17 #include <deque> 18 #include <memory> 19 #include <set> 20 21 namespace clang { 22 namespace ast_matchers { 23 24 static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) { 25 switch (Cmp) { 26 case GtestCmp::Eq: 27 return cxxMethodDecl(hasName("Compare"), 28 ofClass(cxxRecordDecl(isSameOrDerivedFrom( 29 hasName("::testing::internal::EqHelper"))))); 30 case GtestCmp::Ne: 31 return functionDecl(hasName("::testing::internal::CmpHelperNE")); 32 case GtestCmp::Ge: 33 return functionDecl(hasName("::testing::internal::CmpHelperGE")); 34 case GtestCmp::Gt: 35 return functionDecl(hasName("::testing::internal::CmpHelperGT")); 36 case GtestCmp::Le: 37 return functionDecl(hasName("::testing::internal::CmpHelperLE")); 38 case GtestCmp::Lt: 39 return functionDecl(hasName("::testing::internal::CmpHelperLT")); 40 } 41 llvm_unreachable("Unhandled GtestCmp enum"); 42 } 43 44 static llvm::StringRef getAssertMacro(GtestCmp Cmp) { 45 switch (Cmp) { 46 case GtestCmp::Eq: 47 return "ASSERT_EQ"; 48 case GtestCmp::Ne: 49 return "ASSERT_NE"; 50 case GtestCmp::Ge: 51 return "ASSERT_GE"; 52 case GtestCmp::Gt: 53 return "ASSERT_GT"; 54 case GtestCmp::Le: 55 return "ASSERT_LE"; 56 case GtestCmp::Lt: 57 return "ASSERT_LT"; 58 } 59 llvm_unreachable("Unhandled GtestCmp enum"); 60 } 61 62 static llvm::StringRef getExpectMacro(GtestCmp Cmp) { 63 switch (Cmp) { 64 case GtestCmp::Eq: 65 return "EXPECT_EQ"; 66 case GtestCmp::Ne: 67 return "EXPECT_NE"; 68 case GtestCmp::Ge: 69 return "EXPECT_GE"; 70 case GtestCmp::Gt: 71 return "EXPECT_GT"; 72 case GtestCmp::Le: 73 return "EXPECT_LE"; 74 case GtestCmp::Lt: 75 return "EXPECT_LT"; 76 } 77 llvm_unreachable("Unhandled GtestCmp enum"); 78 } 79 80 // In general, AST matchers cannot match calls to macros. However, we can 81 // simulate such matches if the macro definition has identifiable elements that 82 // themselves can be matched. In that case, we can match on those elements and 83 // then check that the match occurs within an expansion of the desired 84 // macro. The more uncommon the identified elements, the more efficient this 85 // process will be. 86 // 87 // We use this approach to implement the derived matchers gtestAssert and 88 // gtestExpect. 89 internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left, 90 StatementMatcher Right) { 91 return callExpr(callee(getComparisonDecl(Cmp)), 92 isExpandedFromMacro(getAssertMacro(Cmp)), 93 hasArgument(2, Left), hasArgument(3, Right)); 94 } 95 96 internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left, 97 StatementMatcher Right) { 98 return callExpr(callee(getComparisonDecl(Cmp)), 99 isExpandedFromMacro(getExpectMacro(Cmp)), 100 hasArgument(2, Left), hasArgument(3, Right)); 101 } 102 103 } // end namespace ast_matchers 104 } // end namespace clang 105