xref: /llvm-project/clang/unittests/Analysis/CFGTest.cpp (revision 92541e359e4bdd2e9a149a2bb7d1519f77244655)
1 //===- unittests/Analysis/CFGTest.cpp - CFG tests -------------------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CFGBuildResult.h"
10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "clang/Analysis/CFG.h"
12 #include "clang/Tooling/Tooling.h"
13 #include "gtest/gtest.h"
14 #include <string>
15 #include <vector>
16 
17 namespace clang {
18 namespace analysis {
19 namespace {
20 
21 // Constructing a CFG for a range-based for over a dependent type fails (but
22 // should not crash).
23 TEST(CFG, RangeBasedForOverDependentType) {
24   const char *Code = "class Foo;\n"
25                      "template <typename T>\n"
26                      "void f(const T &Range) {\n"
27                      "  for (const Foo *TheFoo : Range) {\n"
28                      "  }\n"
29                      "}\n";
30   EXPECT_EQ(BuildResult::SawFunctionBody, BuildCFG(Code).getStatus());
31 }
32 
33 // Constructing a CFG containing a delete expression on a dependent type should
34 // not crash.
35 TEST(CFG, DeleteExpressionOnDependentType) {
36   const char *Code = "template<class T>\n"
37                      "void f(T t) {\n"
38                      "  delete t;\n"
39                      "}\n";
40   EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
41 }
42 
43 // Constructing a CFG on a function template with a variable of incomplete type
44 // should not crash.
45 TEST(CFG, VariableOfIncompleteType) {
46   const char *Code = "template<class T> void f() {\n"
47                      "  class Undefined;\n"
48                      "  Undefined u;\n"
49                      "}\n";
50   EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
51 }
52 
53 TEST(CFG, IsLinear) {
54   auto expectLinear = [](bool IsLinear, const char *Code) {
55     BuildResult B = BuildCFG(Code);
56     EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
57     EXPECT_EQ(IsLinear, B.getCFG()->isLinear());
58   };
59 
60   expectLinear(true,  "void foo() {}");
61   expectLinear(true,  "void foo() { if (true) return; }");
62   expectLinear(true,  "void foo() { if constexpr (false); }");
63   expectLinear(false, "void foo(bool coin) { if (coin) return; }");
64   expectLinear(false, "void foo() { for(;;); }");
65   expectLinear(false, "void foo() { do {} while (true); }");
66   expectLinear(true,  "void foo() { do {} while (false); }");
67   expectLinear(true,  "void foo() { foo(); }"); // Recursion is not our problem.
68 }
69 
70 TEST(CFG, ElementRefIterator) {
71   const char *Code = R"(void f() {
72                           int i;
73                           int j;
74                           i = 5;
75                           i = 6;
76                           j = 7;
77                         })";
78 
79   BuildResult B = BuildCFG(Code);
80   EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
81   CFG *Cfg = B.getCFG();
82 
83   // [B2 (ENTRY)]
84   //   Succs (1): B1
85 
86   // [B1]
87   //   1: int i;
88   //   2: int j;
89   //   3: i = 5
90   //   4: i = 6
91   //   5: j = 7
92   //   Preds (1): B2
93   //   Succs (1): B0
94 
95   // [B0 (EXIT)]
96   //   Preds (1): B1
97   CFGBlock *MainBlock = *(Cfg->begin() + 1);
98 
99   constexpr CFGBlock::ref_iterator::difference_type MainBlockSize = 4;
100 
101   // The rest of this test looks totally insane, but there iterators are
102   // templates under the hood, to it's important to instantiate everything for
103   // proper converage.
104 
105   // Non-reverse, non-const version
106   size_t Index = 0;
107   for (CFGBlock::CFGElementRef ElementRef : MainBlock->refs()) {
108     EXPECT_EQ(ElementRef.getParent(), MainBlock);
109     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
110     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
111     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
112     EXPECT_EQ(ElementRef.getParent(), MainBlock);
113     ++Index;
114   }
115   EXPECT_TRUE(*MainBlock->ref_begin() < *(MainBlock->ref_begin() + 1));
116   EXPECT_TRUE(*MainBlock->ref_begin() == *MainBlock->ref_begin());
117   EXPECT_FALSE(*MainBlock->ref_begin() != *MainBlock->ref_begin());
118 
119   EXPECT_TRUE(MainBlock->ref_begin() < MainBlock->ref_begin() + 1);
120   EXPECT_TRUE(MainBlock->ref_begin() == MainBlock->ref_begin());
121   EXPECT_FALSE(MainBlock->ref_begin() != MainBlock->ref_begin());
122   EXPECT_EQ(MainBlock->ref_end() - MainBlock->ref_begin(), MainBlockSize + 1);
123   EXPECT_EQ(MainBlock->ref_end() - MainBlockSize - 1, MainBlock->ref_begin());
124   EXPECT_EQ(MainBlock->ref_begin() + MainBlockSize + 1, MainBlock->ref_end());
125   EXPECT_EQ(MainBlock->ref_begin()++, MainBlock->ref_begin());
126   EXPECT_EQ(++(MainBlock->ref_begin()), MainBlock->ref_begin() + 1);
127 
128   // Non-reverse, non-const version
129   const CFGBlock *CMainBlock = MainBlock;
130   Index = 0;
131   for (CFGBlock::ConstCFGElementRef ElementRef : CMainBlock->refs()) {
132     EXPECT_EQ(ElementRef.getParent(), CMainBlock);
133     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
134     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
135     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
136     EXPECT_EQ(ElementRef.getParent(), MainBlock);
137     ++Index;
138   }
139   EXPECT_TRUE(*CMainBlock->ref_begin() < *(CMainBlock->ref_begin() + 1));
140   EXPECT_TRUE(*CMainBlock->ref_begin() == *CMainBlock->ref_begin());
141   EXPECT_FALSE(*CMainBlock->ref_begin() != *CMainBlock->ref_begin());
142 
143   EXPECT_TRUE(CMainBlock->ref_begin() < CMainBlock->ref_begin() + 1);
144   EXPECT_TRUE(CMainBlock->ref_begin() == CMainBlock->ref_begin());
145   EXPECT_FALSE(CMainBlock->ref_begin() != CMainBlock->ref_begin());
146   EXPECT_EQ(CMainBlock->ref_end() - CMainBlock->ref_begin(), MainBlockSize + 1);
147   EXPECT_EQ(CMainBlock->ref_end() - MainBlockSize - 1, CMainBlock->ref_begin());
148   EXPECT_EQ(CMainBlock->ref_begin() + MainBlockSize + 1, CMainBlock->ref_end());
149   EXPECT_EQ(CMainBlock->ref_begin()++, CMainBlock->ref_begin());
150   EXPECT_EQ(++(CMainBlock->ref_begin()), CMainBlock->ref_begin() + 1);
151 
152   // Reverse, non-const version
153   Index = MainBlockSize;
154   for (CFGBlock::CFGElementRef ElementRef : MainBlock->rrefs()) {
155     llvm::errs() << Index << '\n';
156     EXPECT_EQ(ElementRef.getParent(), MainBlock);
157     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
158     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
159     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
160     EXPECT_EQ(ElementRef.getParent(), MainBlock);
161     --Index;
162   }
163   EXPECT_FALSE(*MainBlock->rref_begin() < *(MainBlock->rref_begin() + 1));
164   EXPECT_TRUE(*MainBlock->rref_begin() == *MainBlock->rref_begin());
165   EXPECT_FALSE(*MainBlock->rref_begin() != *MainBlock->rref_begin());
166 
167   EXPECT_TRUE(MainBlock->rref_begin() < MainBlock->rref_begin() + 1);
168   EXPECT_TRUE(MainBlock->rref_begin() == MainBlock->rref_begin());
169   EXPECT_FALSE(MainBlock->rref_begin() != MainBlock->rref_begin());
170   EXPECT_EQ(MainBlock->rref_end() - MainBlock->rref_begin(), MainBlockSize + 1);
171   EXPECT_EQ(MainBlock->rref_end() - MainBlockSize - 1, MainBlock->rref_begin());
172   EXPECT_EQ(MainBlock->rref_begin() + MainBlockSize + 1, MainBlock->rref_end());
173   EXPECT_EQ(MainBlock->rref_begin()++, MainBlock->rref_begin());
174   EXPECT_EQ(++(MainBlock->rref_begin()), MainBlock->rref_begin() + 1);
175 
176   // Reverse, const version
177   Index = MainBlockSize;
178   for (CFGBlock::ConstCFGElementRef ElementRef : CMainBlock->rrefs()) {
179     EXPECT_EQ(ElementRef.getParent(), CMainBlock);
180     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
181     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
182     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
183     EXPECT_EQ(ElementRef.getParent(), MainBlock);
184     --Index;
185   }
186   EXPECT_FALSE(*CMainBlock->rref_begin() < *(CMainBlock->rref_begin() + 1));
187   EXPECT_TRUE(*CMainBlock->rref_begin() == *CMainBlock->rref_begin());
188   EXPECT_FALSE(*CMainBlock->rref_begin() != *CMainBlock->rref_begin());
189 
190   EXPECT_TRUE(CMainBlock->rref_begin() < CMainBlock->rref_begin() + 1);
191   EXPECT_TRUE(CMainBlock->rref_begin() == CMainBlock->rref_begin());
192   EXPECT_FALSE(CMainBlock->rref_begin() != CMainBlock->rref_begin());
193   EXPECT_EQ(CMainBlock->rref_end() - CMainBlock->rref_begin(),
194             MainBlockSize + 1);
195   EXPECT_EQ(CMainBlock->rref_end() - MainBlockSize - 1,
196             CMainBlock->rref_begin());
197   EXPECT_EQ(CMainBlock->rref_begin() + MainBlockSize + 1,
198             CMainBlock->rref_end());
199   EXPECT_EQ(CMainBlock->rref_begin()++, CMainBlock->rref_begin());
200   EXPECT_EQ(++(CMainBlock->rref_begin()), CMainBlock->rref_begin() + 1);
201 }
202 
203 } // namespace
204 } // namespace analysis
205 } // namespace clang
206