summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/clang/unittests/Analysis/CFGTest.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
commite5dd70708596ae51455a0ffa086a00c5b29f8583 (patch)
tree5d676f27b570bacf71e786c3b5cff3e6f6679b59 /gnu/llvm/clang/unittests/Analysis/CFGTest.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.tar.xz
wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/clang/unittests/Analysis/CFGTest.cpp')
-rw-r--r--gnu/llvm/clang/unittests/Analysis/CFGTest.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/gnu/llvm/clang/unittests/Analysis/CFGTest.cpp b/gnu/llvm/clang/unittests/Analysis/CFGTest.cpp
new file mode 100644
index 00000000000..1994658bed5
--- /dev/null
+++ b/gnu/llvm/clang/unittests/Analysis/CFGTest.cpp
@@ -0,0 +1,221 @@
+//===- 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());
+}
+
+TEST(CFG, StaticInitializerLastCondition) {
+ const char *Code = "void f() {\n"
+ " int i = 5 ;\n"
+ " static int j = 3 ;\n"
+ "}\n";
+ CFG::BuildOptions Options;
+ Options.AddStaticInitBranches = true;
+ Options.setAllAlwaysAdd();
+ BuildResult B = BuildCFG(Code, Options);
+ EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
+ EXPECT_EQ(1u, B.getCFG()->getEntry().succ_size());
+ CFGBlock *Block = *B.getCFG()->getEntry().succ_begin();
+ EXPECT_TRUE(isa<DeclStmt>(Block->getTerminatorStmt()));
+ EXPECT_EQ(nullptr, Block->getLastCondition());
+}
+
+// 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