//===- unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/MatchSwitch.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/Stmt.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/StringRef.h" #include "gtest/gtest.h" #include #include #include #include #include using namespace clang; using namespace dataflow; using namespace ast_matchers; namespace { TEST(MatchSwitchTest, Stmts) { std::string Code = R"( void Foo(); void Bar(); void f() { int X = 1; Foo(); Bar(); } )"; auto Unit = tooling::buildASTFromCode(Code); auto &Ctx = Unit->getASTContext(); llvm::StringRef XStr = "X"; llvm::StringRef FooStr = "Foo"; llvm::StringRef BarStr = "Bar"; auto XMatcher = declStmt(hasSingleDecl(varDecl(hasName(XStr)))); auto FooMatcher = callExpr(callee(functionDecl(hasName(FooStr)))); auto BarMatcher = callExpr(callee(functionDecl(hasName(BarStr)))); ASTMatchSwitch MS = ASTMatchSwitchBuilder() .CaseOf(XMatcher, [&XStr](const Stmt *, const MatchFinder::MatchResult &, llvm::StringRef &State) { State = XStr; }) .CaseOf(FooMatcher, [&FooStr](const Stmt *, const MatchFinder::MatchResult &, llvm::StringRef &State) { State = FooStr; }) .Build(); llvm::StringRef State; // State modified from the first case of the switch const auto *X = selectFirst(XStr, match(XMatcher.bind(XStr), Ctx)); MS(*X, Ctx, State); EXPECT_EQ(State, XStr); // State modified from the second case of the switch const auto *Foo = selectFirst(FooStr, match(FooMatcher.bind(FooStr), Ctx)); MS(*Foo, Ctx, State); EXPECT_EQ(State, FooStr); // State unmodified, no case defined for calling Bar const auto *Bar = selectFirst(BarStr, match(BarMatcher.bind(BarStr), Ctx)); MS(*Bar, Ctx, State); EXPECT_EQ(State, FooStr); } TEST(MatchSwitchTest, CtorInitializers) { std::string Code = R"( struct f { int i; int j; int z; f(): i(1), j(1), z(1) {} }; )"; auto Unit = tooling::buildASTFromCode(Code); auto &Ctx = Unit->getASTContext(); llvm::StringRef IStr = "i"; llvm::StringRef JStr = "j"; llvm::StringRef ZStr = "z"; auto InitI = cxxCtorInitializer(forField(hasName(IStr))); auto InitJ = cxxCtorInitializer(forField(hasName(JStr))); auto InitZ = cxxCtorInitializer(forField(hasName(ZStr))); ASTMatchSwitch MS = ASTMatchSwitchBuilder() .CaseOf( InitI, [&IStr](const CXXCtorInitializer *, const MatchFinder::MatchResult &, llvm::StringRef &State) { State = IStr; }) .CaseOf( InitJ, [&JStr](const CXXCtorInitializer *, const MatchFinder::MatchResult &, llvm::StringRef &State) { State = JStr; }) .Build(); llvm::StringRef State; // State modified from the first case of the switch const auto *I = selectFirst(IStr, match(InitI.bind(IStr), Ctx)); MS(*I, Ctx, State); EXPECT_EQ(State, IStr); // State modified from the second case of the switch const auto *J = selectFirst(JStr, match(InitJ.bind(JStr), Ctx)); MS(*J, Ctx, State); EXPECT_EQ(State, JStr); // State unmodified, no case defined for the initializer of z const auto *Z = selectFirst(ZStr, match(InitZ.bind(ZStr), Ctx)); MS(*Z, Ctx, State); EXPECT_EQ(State, JStr); } TEST(MatchSwitchTest, ReturnNonVoid) { auto Unit = tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc", std::make_shared()); auto &Context = Unit->getASTContext(); const auto *S = selectFirst( "f", match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context)) ->getBody(); ASTMatchSwitch> Switch = ASTMatchSwitchBuilder>() .CaseOf(stmt(), [](const Stmt *, const MatchFinder::MatchResult &, const int &State) -> std::vector { return {1, State, 3}; }) .Build(); std::vector Actual = Switch(*S, Context, 7); std::vector Expected{1, 7, 3}; EXPECT_EQ(Actual, Expected); } } // namespace