160 lines · cpp
1//===- unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp ---------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Analysis/FlowSensitive/MatchSwitch.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Decl.h"12#include "clang/AST/DeclCXX.h"13#include "clang/AST/Expr.h"14#include "clang/AST/Stmt.h"15#include "clang/ASTMatchers/ASTMatchFinder.h"16#include "clang/ASTMatchers/ASTMatchers.h"17#include "clang/Tooling/Tooling.h"18#include "llvm/ADT/StringRef.h"19#include "gtest/gtest.h"20#include <cstdint>21#include <memory>22#include <ostream>23#include <string>24#include <utility>25 26using namespace clang;27using namespace dataflow;28using namespace ast_matchers;29 30namespace {31 32TEST(MatchSwitchTest, Stmts) {33 std::string Code = R"(34 void Foo();35 void Bar();36 void f() {37 int X = 1;38 Foo();39 Bar();40 }41 )";42 auto Unit = tooling::buildASTFromCode(Code);43 auto &Ctx = Unit->getASTContext();44 45 llvm::StringRef XStr = "X";46 llvm::StringRef FooStr = "Foo";47 llvm::StringRef BarStr = "Bar";48 49 auto XMatcher = declStmt(hasSingleDecl(varDecl(hasName(XStr))));50 auto FooMatcher = callExpr(callee(functionDecl(hasName(FooStr))));51 auto BarMatcher = callExpr(callee(functionDecl(hasName(BarStr))));52 53 ASTMatchSwitch<Stmt, llvm::StringRef> MS =54 ASTMatchSwitchBuilder<Stmt, llvm::StringRef>()55 .CaseOf<Stmt>(XMatcher,56 [&XStr](const Stmt *, const MatchFinder::MatchResult &,57 llvm::StringRef &State) { State = XStr; })58 .CaseOf<Stmt>(FooMatcher,59 [&FooStr](const Stmt *,60 const MatchFinder::MatchResult &,61 llvm::StringRef &State) { State = FooStr; })62 .Build();63 llvm::StringRef State;64 65 // State modified from the first case of the switch66 const auto *X = selectFirst<Stmt>(XStr, match(XMatcher.bind(XStr), Ctx));67 MS(*X, Ctx, State);68 EXPECT_EQ(State, XStr);69 70 // State modified from the second case of the switch71 const auto *Foo =72 selectFirst<Stmt>(FooStr, match(FooMatcher.bind(FooStr), Ctx));73 MS(*Foo, Ctx, State);74 EXPECT_EQ(State, FooStr);75 76 // State unmodified, no case defined for calling Bar77 const auto *Bar =78 selectFirst<Stmt>(BarStr, match(BarMatcher.bind(BarStr), Ctx));79 MS(*Bar, Ctx, State);80 EXPECT_EQ(State, FooStr);81}82 83TEST(MatchSwitchTest, CtorInitializers) {84 std::string Code = R"(85 struct f {86 int i;87 int j;88 int z;89 f(): i(1), j(1), z(1) {}90 };91 )";92 auto Unit = tooling::buildASTFromCode(Code);93 auto &Ctx = Unit->getASTContext();94 95 llvm::StringRef IStr = "i";96 llvm::StringRef JStr = "j";97 llvm::StringRef ZStr = "z";98 99 auto InitI = cxxCtorInitializer(forField(hasName(IStr)));100 auto InitJ = cxxCtorInitializer(forField(hasName(JStr)));101 auto InitZ = cxxCtorInitializer(forField(hasName(ZStr)));102 103 ASTMatchSwitch<CXXCtorInitializer, llvm::StringRef> MS =104 ASTMatchSwitchBuilder<CXXCtorInitializer, llvm::StringRef>()105 .CaseOf<CXXCtorInitializer>(106 InitI, [&IStr](const CXXCtorInitializer *,107 const MatchFinder::MatchResult &,108 llvm::StringRef &State) { State = IStr; })109 .CaseOf<CXXCtorInitializer>(110 InitJ, [&JStr](const CXXCtorInitializer *,111 const MatchFinder::MatchResult &,112 llvm::StringRef &State) { State = JStr; })113 .Build();114 llvm::StringRef State;115 116 // State modified from the first case of the switch117 const auto *I =118 selectFirst<CXXCtorInitializer>(IStr, match(InitI.bind(IStr), Ctx));119 MS(*I, Ctx, State);120 EXPECT_EQ(State, IStr);121 122 // State modified from the second case of the switch123 const auto *J =124 selectFirst<CXXCtorInitializer>(JStr, match(InitJ.bind(JStr), Ctx));125 MS(*J, Ctx, State);126 EXPECT_EQ(State, JStr);127 128 // State unmodified, no case defined for the initializer of z129 const auto *Z =130 selectFirst<CXXCtorInitializer>(ZStr, match(InitZ.bind(ZStr), Ctx));131 MS(*Z, Ctx, State);132 EXPECT_EQ(State, JStr);133}134 135TEST(MatchSwitchTest, ReturnNonVoid) {136 auto Unit =137 tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc",138 std::make_shared<PCHContainerOperations>());139 auto &Context = Unit->getASTContext();140 const auto *S =141 selectFirst<FunctionDecl>(142 "f",143 match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context))144 ->getBody();145 146 ASTMatchSwitch<Stmt, const int, std::vector<int>> Switch =147 ASTMatchSwitchBuilder<Stmt, const int, std::vector<int>>()148 .CaseOf<Stmt>(stmt(),149 [](const Stmt *, const MatchFinder::MatchResult &,150 const int &State) -> std::vector<int> {151 return {1, State, 3};152 })153 .Build();154 std::vector<int> Actual = Switch(*S, Context, 7);155 std::vector<int> Expected{1, 7, 3};156 EXPECT_EQ(Actual, Expected);157}158 159} // namespace160