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