123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- //===- unittests/Analysis/CFGTest.cpp - CFG tests -------------------------===//
- //
- // 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 "CFGBuildResult.h"
- #include "clang/ASTMatchers/ASTMatchFinder.h"
- #include "clang/Analysis/CFG.h"
- #include "clang/Tooling/Tooling.h"
- #include "gtest/gtest.h"
- #include <string>
- #include <vector>
- namespace clang {
- namespace analysis {
- namespace {
- // Constructing a CFG for a range-based for over a dependent type fails (but
- // should not crash).
- TEST(CFG, RangeBasedForOverDependentType) {
- const char *Code = "class Foo;\n"
- "template <typename T>\n"
- "void f(const T &Range) {\n"
- " for (const Foo *TheFoo : Range) {\n"
- " }\n"
- "}\n";
- EXPECT_EQ(BuildResult::SawFunctionBody, BuildCFG(Code).getStatus());
- }
- // Constructing a CFG containing a delete expression on a dependent type should
- // not crash.
- TEST(CFG, DeleteExpressionOnDependentType) {
- const char *Code = "template<class T>\n"
- "void f(T t) {\n"
- " delete t;\n"
- "}\n";
- EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
- }
- // Constructing a CFG on a function template with a variable of incomplete type
- // should not crash.
- TEST(CFG, VariableOfIncompleteType) {
- const char *Code = "template<class T> void f() {\n"
- " class Undefined;\n"
- " Undefined u;\n"
- "}\n";
- EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
- }
- TEST(CFG, IsLinear) {
- auto expectLinear = [](bool IsLinear, const char *Code) {
- BuildResult B = BuildCFG(Code);
- EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
- EXPECT_EQ(IsLinear, B.getCFG()->isLinear());
- };
- expectLinear(true, "void foo() {}");
- expectLinear(true, "void foo() { if (true) return; }");
- expectLinear(true, "void foo() { if constexpr (false); }");
- expectLinear(false, "void foo(bool coin) { if (coin) return; }");
- expectLinear(false, "void foo() { for(;;); }");
- expectLinear(false, "void foo() { do {} while (true); }");
- expectLinear(true, "void foo() { do {} while (false); }");
- expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
- }
- TEST(CFG, ElementRefIterator) {
- const char *Code = R"(void f() {
- int i;
- int j;
- i = 5;
- i = 6;
- j = 7;
- })";
- BuildResult B = BuildCFG(Code);
- EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
- CFG *Cfg = B.getCFG();
- // [B2 (ENTRY)]
- // Succs (1): B1
- // [B1]
- // 1: int i;
- // 2: int j;
- // 3: i = 5
- // 4: i = 6
- // 5: j = 7
- // Preds (1): B2
- // Succs (1): B0
- // [B0 (EXIT)]
- // Preds (1): B1
- CFGBlock *MainBlock = *(Cfg->begin() + 1);
- constexpr CFGBlock::ref_iterator::difference_type MainBlockSize = 4;
- // The rest of this test looks totally insane, but there iterators are
- // templates under the hood, to it's important to instantiate everything for
- // proper converage.
- // Non-reverse, non-const version
- size_t Index = 0;
- for (CFGBlock::CFGElementRef ElementRef : MainBlock->refs()) {
- EXPECT_EQ(ElementRef.getParent(), MainBlock);
- EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
- EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
- EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
- EXPECT_EQ(ElementRef.getParent(), MainBlock);
- ++Index;
- }
- EXPECT_TRUE(*MainBlock->ref_begin() < *(MainBlock->ref_begin() + 1));
- EXPECT_TRUE(*MainBlock->ref_begin() == *MainBlock->ref_begin());
- EXPECT_FALSE(*MainBlock->ref_begin() != *MainBlock->ref_begin());
- EXPECT_TRUE(MainBlock->ref_begin() < MainBlock->ref_begin() + 1);
- EXPECT_TRUE(MainBlock->ref_begin() == MainBlock->ref_begin());
- EXPECT_FALSE(MainBlock->ref_begin() != MainBlock->ref_begin());
- EXPECT_EQ(MainBlock->ref_end() - MainBlock->ref_begin(), MainBlockSize + 1);
- EXPECT_EQ(MainBlock->ref_end() - MainBlockSize - 1, MainBlock->ref_begin());
- EXPECT_EQ(MainBlock->ref_begin() + MainBlockSize + 1, MainBlock->ref_end());
- EXPECT_EQ(MainBlock->ref_begin()++, MainBlock->ref_begin());
- EXPECT_EQ(++(MainBlock->ref_begin()), MainBlock->ref_begin() + 1);
- // Non-reverse, non-const version
- const CFGBlock *CMainBlock = MainBlock;
- Index = 0;
- for (CFGBlock::ConstCFGElementRef ElementRef : CMainBlock->refs()) {
- EXPECT_EQ(ElementRef.getParent(), CMainBlock);
- EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
- EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
- EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
- EXPECT_EQ(ElementRef.getParent(), MainBlock);
- ++Index;
- }
- EXPECT_TRUE(*CMainBlock->ref_begin() < *(CMainBlock->ref_begin() + 1));
- EXPECT_TRUE(*CMainBlock->ref_begin() == *CMainBlock->ref_begin());
- EXPECT_FALSE(*CMainBlock->ref_begin() != *CMainBlock->ref_begin());
- EXPECT_TRUE(CMainBlock->ref_begin() < CMainBlock->ref_begin() + 1);
- EXPECT_TRUE(CMainBlock->ref_begin() == CMainBlock->ref_begin());
- EXPECT_FALSE(CMainBlock->ref_begin() != CMainBlock->ref_begin());
- EXPECT_EQ(CMainBlock->ref_end() - CMainBlock->ref_begin(), MainBlockSize + 1);
- EXPECT_EQ(CMainBlock->ref_end() - MainBlockSize - 1, CMainBlock->ref_begin());
- EXPECT_EQ(CMainBlock->ref_begin() + MainBlockSize + 1, CMainBlock->ref_end());
- EXPECT_EQ(CMainBlock->ref_begin()++, CMainBlock->ref_begin());
- EXPECT_EQ(++(CMainBlock->ref_begin()), CMainBlock->ref_begin() + 1);
- // Reverse, non-const version
- Index = MainBlockSize;
- for (CFGBlock::CFGElementRef ElementRef : MainBlock->rrefs()) {
- llvm::errs() << Index << '\n';
- EXPECT_EQ(ElementRef.getParent(), MainBlock);
- EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
- EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
- EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
- EXPECT_EQ(ElementRef.getParent(), MainBlock);
- --Index;
- }
- EXPECT_FALSE(*MainBlock->rref_begin() < *(MainBlock->rref_begin() + 1));
- EXPECT_TRUE(*MainBlock->rref_begin() == *MainBlock->rref_begin());
- EXPECT_FALSE(*MainBlock->rref_begin() != *MainBlock->rref_begin());
- EXPECT_TRUE(MainBlock->rref_begin() < MainBlock->rref_begin() + 1);
- EXPECT_TRUE(MainBlock->rref_begin() == MainBlock->rref_begin());
- EXPECT_FALSE(MainBlock->rref_begin() != MainBlock->rref_begin());
- EXPECT_EQ(MainBlock->rref_end() - MainBlock->rref_begin(), MainBlockSize + 1);
- EXPECT_EQ(MainBlock->rref_end() - MainBlockSize - 1, MainBlock->rref_begin());
- EXPECT_EQ(MainBlock->rref_begin() + MainBlockSize + 1, MainBlock->rref_end());
- EXPECT_EQ(MainBlock->rref_begin()++, MainBlock->rref_begin());
- EXPECT_EQ(++(MainBlock->rref_begin()), MainBlock->rref_begin() + 1);
- // Reverse, const version
- Index = MainBlockSize;
- for (CFGBlock::ConstCFGElementRef ElementRef : CMainBlock->rrefs()) {
- EXPECT_EQ(ElementRef.getParent(), CMainBlock);
- EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
- EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
- EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
- EXPECT_EQ(ElementRef.getParent(), MainBlock);
- --Index;
- }
- EXPECT_FALSE(*CMainBlock->rref_begin() < *(CMainBlock->rref_begin() + 1));
- EXPECT_TRUE(*CMainBlock->rref_begin() == *CMainBlock->rref_begin());
- EXPECT_FALSE(*CMainBlock->rref_begin() != *CMainBlock->rref_begin());
- EXPECT_TRUE(CMainBlock->rref_begin() < CMainBlock->rref_begin() + 1);
- EXPECT_TRUE(CMainBlock->rref_begin() == CMainBlock->rref_begin());
- EXPECT_FALSE(CMainBlock->rref_begin() != CMainBlock->rref_begin());
- EXPECT_EQ(CMainBlock->rref_end() - CMainBlock->rref_begin(),
- MainBlockSize + 1);
- EXPECT_EQ(CMainBlock->rref_end() - MainBlockSize - 1,
- CMainBlock->rref_begin());
- EXPECT_EQ(CMainBlock->rref_begin() + MainBlockSize + 1,
- CMainBlock->rref_end());
- EXPECT_EQ(CMainBlock->rref_begin()++, CMainBlock->rref_begin());
- EXPECT_EQ(++(CMainBlock->rref_begin()), CMainBlock->rref_begin() + 1);
- }
- } // namespace
- } // namespace analysis
- } // namespace clang
|