Path: blob/main/contrib/llvm-project/clang/lib/ASTMatchers/GtestMatchers.cpp
35262 views
//===- GtestMatchers.cpp - AST Matchers for Gtest ---------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements several matchers for popular gtest macros. In general,9// AST matchers cannot match calls to macros. However, we can simulate such10// matches if the macro definition has identifiable elements that themselves can11// be matched. In that case, we can match on those elements and then check that12// the match occurs within an expansion of the desired macro. The more uncommon13// the identified elements, the more efficient this process will be.14//15//===----------------------------------------------------------------------===//1617#include "clang/ASTMatchers/GtestMatchers.h"18#include "clang/AST/ASTConsumer.h"19#include "clang/AST/ASTContext.h"20#include "clang/AST/RecursiveASTVisitor.h"21#include "clang/ASTMatchers/ASTMatchFinder.h"22#include "llvm/ADT/DenseMap.h"23#include "llvm/ADT/StringRef.h"2425namespace clang {26namespace ast_matchers {27namespace {2829enum class MacroType {30Expect,31Assert,32On,33};3435} // namespace3637static DeclarationMatcher getComparisonDecl(GtestCmp Cmp) {38switch (Cmp) {39case GtestCmp::Eq:40return cxxMethodDecl(hasName("Compare"),41ofClass(cxxRecordDecl(isSameOrDerivedFrom(42hasName("::testing::internal::EqHelper")))));43case GtestCmp::Ne:44return functionDecl(hasName("::testing::internal::CmpHelperNE"));45case GtestCmp::Ge:46return functionDecl(hasName("::testing::internal::CmpHelperGE"));47case GtestCmp::Gt:48return functionDecl(hasName("::testing::internal::CmpHelperGT"));49case GtestCmp::Le:50return functionDecl(hasName("::testing::internal::CmpHelperLE"));51case GtestCmp::Lt:52return functionDecl(hasName("::testing::internal::CmpHelperLT"));53}54llvm_unreachable("Unhandled GtestCmp enum");55}5657static llvm::StringRef getMacroTypeName(MacroType Macro) {58switch (Macro) {59case MacroType::Expect:60return "EXPECT";61case MacroType::Assert:62return "ASSERT";63case MacroType::On:64return "ON";65}66llvm_unreachable("Unhandled MacroType enum");67}6869static llvm::StringRef getComparisonTypeName(GtestCmp Cmp) {70switch (Cmp) {71case GtestCmp::Eq:72return "EQ";73case GtestCmp::Ne:74return "NE";75case GtestCmp::Ge:76return "GE";77case GtestCmp::Gt:78return "GT";79case GtestCmp::Le:80return "LE";81case GtestCmp::Lt:82return "LT";83}84llvm_unreachable("Unhandled GtestCmp enum");85}8687static std::string getMacroName(MacroType Macro, GtestCmp Cmp) {88return (getMacroTypeName(Macro) + "_" + getComparisonTypeName(Cmp)).str();89}9091static std::string getMacroName(MacroType Macro, llvm::StringRef Operation) {92return (getMacroTypeName(Macro) + "_" + Operation).str();93}9495// Under the hood, ON_CALL is expanded to a call to `InternalDefaultActionSetAt`96// to set a default action spec to the underlying function mocker, while97// EXPECT_CALL is expanded to a call to `InternalExpectedAt` to set a new98// expectation spec.99static llvm::StringRef getSpecSetterName(MacroType Macro) {100switch (Macro) {101case MacroType::On:102return "InternalDefaultActionSetAt";103case MacroType::Expect:104return "InternalExpectedAt";105default:106llvm_unreachable("Unhandled MacroType enum");107}108llvm_unreachable("Unhandled MacroType enum");109}110111// In general, AST matchers cannot match calls to macros. However, we can112// simulate such matches if the macro definition has identifiable elements that113// themselves can be matched. In that case, we can match on those elements and114// then check that the match occurs within an expansion of the desired115// macro. The more uncommon the identified elements, the more efficient this116// process will be.117//118// We use this approach to implement the derived matchers gtestAssert and119// gtestExpect.120static internal::BindableMatcher<Stmt>121gtestComparisonInternal(MacroType Macro, GtestCmp Cmp, StatementMatcher Left,122StatementMatcher Right) {123return callExpr(isExpandedFromMacro(getMacroName(Macro, Cmp)),124callee(getComparisonDecl(Cmp)), hasArgument(2, Left),125hasArgument(3, Right));126}127128static internal::BindableMatcher<Stmt>129gtestThatInternal(MacroType Macro, StatementMatcher Actual,130StatementMatcher Matcher) {131return cxxOperatorCallExpr(132isExpandedFromMacro(getMacroName(Macro, "THAT")),133hasOverloadedOperatorName("()"), hasArgument(2, Actual),134hasArgument(1350, expr(hasType(classTemplateSpecializationDecl(hasName(136"::testing::internal::PredicateFormatterFromMatcher"))),137ignoringImplicit(138callExpr(callee(functionDecl(hasName(139"::testing::internal::"140"MakePredicateFormatterFromMatcher"))),141hasArgument(0, ignoringImplicit(Matcher)))))));142}143144static internal::BindableMatcher<Stmt>145gtestCallInternal(MacroType Macro, StatementMatcher MockCall, MockArgs Args) {146// A ON_CALL or EXPECT_CALL macro expands to different AST structures147// depending on whether the mock method has arguments or not.148switch (Args) {149// For example,150// `ON_CALL(mock, TwoParamMethod)` is expanded to151// `mock.gmock_TwoArgsMethod(WithoutMatchers(),152// nullptr).InternalDefaultActionSetAt(...)`.153// EXPECT_CALL is the same except154// that it calls `InternalExpectedAt` instead of `InternalDefaultActionSetAt`155// in the end.156case MockArgs::None:157return cxxMemberCallExpr(158isExpandedFromMacro(getMacroName(Macro, "CALL")),159callee(functionDecl(hasName(getSpecSetterName(Macro)))),160onImplicitObjectArgument(ignoringImplicit(MockCall)));161// For example,162// `ON_CALL(mock, TwoParamMethod(m1, m2))` is expanded to163// `mock.gmock_TwoParamMethod(m1,m2)(WithoutMatchers(),164// nullptr).InternalDefaultActionSetAt(...)`.165// EXPECT_CALL is the same except that it calls `InternalExpectedAt` instead166// of `InternalDefaultActionSetAt` in the end.167case MockArgs::Some:168return cxxMemberCallExpr(169isExpandedFromMacro(getMacroName(Macro, "CALL")),170callee(functionDecl(hasName(getSpecSetterName(Macro)))),171onImplicitObjectArgument(ignoringImplicit(cxxOperatorCallExpr(172hasOverloadedOperatorName("()"), argumentCountIs(3),173hasArgument(0, ignoringImplicit(MockCall))))));174}175llvm_unreachable("Unhandled MockArgs enum");176}177178static internal::BindableMatcher<Stmt>179gtestCallInternal(MacroType Macro, StatementMatcher MockObject,180llvm::StringRef MockMethodName, MockArgs Args) {181return gtestCallInternal(182Macro,183cxxMemberCallExpr(184onImplicitObjectArgument(MockObject),185callee(functionDecl(hasName(("gmock_" + MockMethodName).str())))),186Args);187}188189internal::BindableMatcher<Stmt> gtestAssert(GtestCmp Cmp, StatementMatcher Left,190StatementMatcher Right) {191return gtestComparisonInternal(MacroType::Assert, Cmp, Left, Right);192}193194internal::BindableMatcher<Stmt> gtestExpect(GtestCmp Cmp, StatementMatcher Left,195StatementMatcher Right) {196return gtestComparisonInternal(MacroType::Expect, Cmp, Left, Right);197}198199internal::BindableMatcher<Stmt> gtestAssertThat(StatementMatcher Actual,200StatementMatcher Matcher) {201return gtestThatInternal(MacroType::Assert, Actual, Matcher);202}203204internal::BindableMatcher<Stmt> gtestExpectThat(StatementMatcher Actual,205StatementMatcher Matcher) {206return gtestThatInternal(MacroType::Expect, Actual, Matcher);207}208209internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockObject,210llvm::StringRef MockMethodName,211MockArgs Args) {212return gtestCallInternal(MacroType::On, MockObject, MockMethodName, Args);213}214215internal::BindableMatcher<Stmt> gtestOnCall(StatementMatcher MockCall,216MockArgs Args) {217return gtestCallInternal(MacroType::On, MockCall, Args);218}219220internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockObject,221llvm::StringRef MockMethodName,222MockArgs Args) {223return gtestCallInternal(MacroType::Expect, MockObject, MockMethodName, Args);224}225226internal::BindableMatcher<Stmt> gtestExpectCall(StatementMatcher MockCall,227MockArgs Args) {228return gtestCallInternal(MacroType::Expect, MockCall, Args);229}230231} // end namespace ast_matchers232} // end namespace clang233234235