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/AST/Decl.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Analysis/AnalysisDeclContext.h"
13 #include "clang/Analysis/CFG.h"
14 #include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "gtest/gtest.h"
17 #include <algorithm>
18 #include <string>
19 #include <vector>
20 
21 namespace clang {
22 namespace analysis {
23 namespace {
24 
25 // Constructing a CFG for a range-based for over a dependent type fails (but
26 // should not crash).
TEST(CFG,RangeBasedForOverDependentType)27 TEST(CFG, RangeBasedForOverDependentType) {
28   const char *Code = "class Foo;\n"
29                      "template <typename T>\n"
30                      "void f(const T &Range) {\n"
31                      "  for (const Foo *TheFoo : Range) {\n"
32                      "  }\n"
33                      "}\n";
34   EXPECT_EQ(BuildResult::SawFunctionBody, BuildCFG(Code).getStatus());
35 }
36 
TEST(CFG,StaticInitializerLastCondition)37 TEST(CFG, StaticInitializerLastCondition) {
38   const char *Code = "void f() {\n"
39                      "  int i = 5 ;\n"
40                      "  static int j = 3 ;\n"
41                      "}\n";
42   CFG::BuildOptions Options;
43   Options.AddStaticInitBranches = true;
44   Options.setAllAlwaysAdd();
45   BuildResult B = BuildCFG(Code, Options);
46   EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
47   EXPECT_EQ(1u, B.getCFG()->getEntry().succ_size());
48   CFGBlock *Block = *B.getCFG()->getEntry().succ_begin();
49   EXPECT_TRUE(isa<DeclStmt>(Block->getTerminatorStmt()));
50   EXPECT_EQ(nullptr, Block->getLastCondition());
51 }
52 
53 // Constructing a CFG containing a delete expression on a dependent type should
54 // not crash.
TEST(CFG,DeleteExpressionOnDependentType)55 TEST(CFG, DeleteExpressionOnDependentType) {
56   const char *Code = "template<class T>\n"
57                      "void f(T t) {\n"
58                      "  delete t;\n"
59                      "}\n";
60   EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
61 }
62 
63 // Constructing a CFG on a function template with a variable of incomplete type
64 // should not crash.
TEST(CFG,VariableOfIncompleteType)65 TEST(CFG, VariableOfIncompleteType) {
66   const char *Code = "template<class T> void f() {\n"
67                      "  class Undefined;\n"
68                      "  Undefined u;\n"
69                      "}\n";
70   EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
71 }
72 
TEST(CFG,IsLinear)73 TEST(CFG, IsLinear) {
74   auto expectLinear = [](bool IsLinear, const char *Code) {
75     BuildResult B = BuildCFG(Code);
76     EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
77     EXPECT_EQ(IsLinear, B.getCFG()->isLinear());
78   };
79 
80   expectLinear(true, "void foo() {}");
81   expectLinear(true, "void foo() { if (true) return; }");
82   expectLinear(true, "void foo() { if constexpr (false); }");
83   expectLinear(false, "void foo(bool coin) { if (coin) return; }");
84   expectLinear(false, "void foo() { for(;;); }");
85   expectLinear(false, "void foo() { do {} while (true); }");
86   expectLinear(true, "void foo() { do {} while (false); }");
87   expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
88 }
89 
TEST(CFG,ElementRefIterator)90 TEST(CFG, ElementRefIterator) {
91   const char *Code = R"(void f() {
92                           int i;
93                           int j;
94                           i = 5;
95                           i = 6;
96                           j = 7;
97                         })";
98 
99   BuildResult B = BuildCFG(Code);
100   EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
101   CFG *Cfg = B.getCFG();
102 
103   // [B2 (ENTRY)]
104   //   Succs (1): B1
105 
106   // [B1]
107   //   1: int i;
108   //   2: int j;
109   //   3: i = 5
110   //   4: i = 6
111   //   5: j = 7
112   //   Preds (1): B2
113   //   Succs (1): B0
114 
115   // [B0 (EXIT)]
116   //   Preds (1): B1
117   CFGBlock *MainBlock = *(Cfg->begin() + 1);
118 
119   constexpr CFGBlock::ref_iterator::difference_type MainBlockSize = 4;
120 
121   // The rest of this test looks totally insane, but there iterators are
122   // templates under the hood, to it's important to instantiate everything for
123   // proper converage.
124 
125   // Non-reverse, non-const version
126   size_t Index = 0;
127   for (CFGBlock::CFGElementRef ElementRef : MainBlock->refs()) {
128     EXPECT_EQ(ElementRef.getParent(), MainBlock);
129     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
130     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
131     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
132     EXPECT_EQ(ElementRef.getParent(), MainBlock);
133     ++Index;
134   }
135   EXPECT_TRUE(*MainBlock->ref_begin() < *(MainBlock->ref_begin() + 1));
136   EXPECT_TRUE(*MainBlock->ref_begin() == *MainBlock->ref_begin());
137   EXPECT_FALSE(*MainBlock->ref_begin() != *MainBlock->ref_begin());
138 
139   EXPECT_TRUE(MainBlock->ref_begin() < MainBlock->ref_begin() + 1);
140   EXPECT_TRUE(MainBlock->ref_begin() == MainBlock->ref_begin());
141   EXPECT_FALSE(MainBlock->ref_begin() != MainBlock->ref_begin());
142   EXPECT_EQ(MainBlock->ref_end() - MainBlock->ref_begin(), MainBlockSize + 1);
143   EXPECT_EQ(MainBlock->ref_end() - MainBlockSize - 1, MainBlock->ref_begin());
144   EXPECT_EQ(MainBlock->ref_begin() + MainBlockSize + 1, MainBlock->ref_end());
145   EXPECT_EQ(MainBlock->ref_begin()++, MainBlock->ref_begin());
146   EXPECT_EQ(++(MainBlock->ref_begin()), MainBlock->ref_begin() + 1);
147 
148   // Non-reverse, non-const version
149   const CFGBlock *CMainBlock = MainBlock;
150   Index = 0;
151   for (CFGBlock::ConstCFGElementRef ElementRef : CMainBlock->refs()) {
152     EXPECT_EQ(ElementRef.getParent(), CMainBlock);
153     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
154     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
155     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
156     EXPECT_EQ(ElementRef.getParent(), MainBlock);
157     ++Index;
158   }
159   EXPECT_TRUE(*CMainBlock->ref_begin() < *(CMainBlock->ref_begin() + 1));
160   EXPECT_TRUE(*CMainBlock->ref_begin() == *CMainBlock->ref_begin());
161   EXPECT_FALSE(*CMainBlock->ref_begin() != *CMainBlock->ref_begin());
162 
163   EXPECT_TRUE(CMainBlock->ref_begin() < CMainBlock->ref_begin() + 1);
164   EXPECT_TRUE(CMainBlock->ref_begin() == CMainBlock->ref_begin());
165   EXPECT_FALSE(CMainBlock->ref_begin() != CMainBlock->ref_begin());
166   EXPECT_EQ(CMainBlock->ref_end() - CMainBlock->ref_begin(), MainBlockSize + 1);
167   EXPECT_EQ(CMainBlock->ref_end() - MainBlockSize - 1, CMainBlock->ref_begin());
168   EXPECT_EQ(CMainBlock->ref_begin() + MainBlockSize + 1, CMainBlock->ref_end());
169   EXPECT_EQ(CMainBlock->ref_begin()++, CMainBlock->ref_begin());
170   EXPECT_EQ(++(CMainBlock->ref_begin()), CMainBlock->ref_begin() + 1);
171 
172   // Reverse, non-const version
173   Index = MainBlockSize;
174   for (CFGBlock::CFGElementRef ElementRef : MainBlock->rrefs()) {
175     llvm::errs() << Index << '\n';
176     EXPECT_EQ(ElementRef.getParent(), MainBlock);
177     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
178     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
179     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
180     EXPECT_EQ(ElementRef.getParent(), MainBlock);
181     --Index;
182   }
183   EXPECT_FALSE(*MainBlock->rref_begin() < *(MainBlock->rref_begin() + 1));
184   EXPECT_TRUE(*MainBlock->rref_begin() == *MainBlock->rref_begin());
185   EXPECT_FALSE(*MainBlock->rref_begin() != *MainBlock->rref_begin());
186 
187   EXPECT_TRUE(MainBlock->rref_begin() < MainBlock->rref_begin() + 1);
188   EXPECT_TRUE(MainBlock->rref_begin() == MainBlock->rref_begin());
189   EXPECT_FALSE(MainBlock->rref_begin() != MainBlock->rref_begin());
190   EXPECT_EQ(MainBlock->rref_end() - MainBlock->rref_begin(), MainBlockSize + 1);
191   EXPECT_EQ(MainBlock->rref_end() - MainBlockSize - 1, MainBlock->rref_begin());
192   EXPECT_EQ(MainBlock->rref_begin() + MainBlockSize + 1, MainBlock->rref_end());
193   EXPECT_EQ(MainBlock->rref_begin()++, MainBlock->rref_begin());
194   EXPECT_EQ(++(MainBlock->rref_begin()), MainBlock->rref_begin() + 1);
195 
196   // Reverse, const version
197   Index = MainBlockSize;
198   for (CFGBlock::ConstCFGElementRef ElementRef : CMainBlock->rrefs()) {
199     EXPECT_EQ(ElementRef.getParent(), CMainBlock);
200     EXPECT_EQ(ElementRef.getIndexInBlock(), Index);
201     EXPECT_TRUE(ElementRef->getAs<CFGStmt>());
202     EXPECT_TRUE((*ElementRef).getAs<CFGStmt>());
203     EXPECT_EQ(ElementRef.getParent(), MainBlock);
204     --Index;
205   }
206   EXPECT_FALSE(*CMainBlock->rref_begin() < *(CMainBlock->rref_begin() + 1));
207   EXPECT_TRUE(*CMainBlock->rref_begin() == *CMainBlock->rref_begin());
208   EXPECT_FALSE(*CMainBlock->rref_begin() != *CMainBlock->rref_begin());
209 
210   EXPECT_TRUE(CMainBlock->rref_begin() < CMainBlock->rref_begin() + 1);
211   EXPECT_TRUE(CMainBlock->rref_begin() == CMainBlock->rref_begin());
212   EXPECT_FALSE(CMainBlock->rref_begin() != CMainBlock->rref_begin());
213   EXPECT_EQ(CMainBlock->rref_end() - CMainBlock->rref_begin(),
214             MainBlockSize + 1);
215   EXPECT_EQ(CMainBlock->rref_end() - MainBlockSize - 1,
216             CMainBlock->rref_begin());
217   EXPECT_EQ(CMainBlock->rref_begin() + MainBlockSize + 1,
218             CMainBlock->rref_end());
219   EXPECT_EQ(CMainBlock->rref_begin()++, CMainBlock->rref_begin());
220   EXPECT_EQ(++(CMainBlock->rref_begin()), CMainBlock->rref_begin() + 1);
221 }
222 
TEST(CFG,Worklists)223 TEST(CFG, Worklists) {
224   const char *Code = "int f(bool cond) {\n"
225                      "  int a = 5;\n"
226                      "  if (cond)\n"
227                      "    a += 1;\n"
228                      "  return a;\n"
229                      "}\n";
230   BuildResult B = BuildCFG(Code);
231   EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
232   const FunctionDecl *Func = B.getFunc();
233   AnalysisDeclContext AC(nullptr, Func);
234   auto *CFG = AC.getCFG();
235 
236   std::vector<const CFGBlock *> ReferenceOrder;
237   for (const auto *B : *AC.getAnalysis<PostOrderCFGView>())
238     ReferenceOrder.push_back(B);
239 
240   {
241     ForwardDataflowWorklist ForwardWorklist(*CFG, AC);
242     for (const auto *B : *CFG)
243       ForwardWorklist.enqueueBlock(B);
244 
245     std::vector<const CFGBlock *> ForwardNodes;
246     while (const CFGBlock *B = ForwardWorklist.dequeue())
247       ForwardNodes.push_back(B);
248 
249     EXPECT_EQ(ForwardNodes.size(), ReferenceOrder.size());
250     EXPECT_TRUE(std::equal(ReferenceOrder.begin(), ReferenceOrder.end(),
251                            ForwardNodes.begin()));
252   }
253 
254   std::reverse(ReferenceOrder.begin(), ReferenceOrder.end());
255 
256   {
257     BackwardDataflowWorklist BackwardWorklist(*CFG, AC);
258     for (const auto *B : *CFG)
259       BackwardWorklist.enqueueBlock(B);
260 
261     std::vector<const CFGBlock *> BackwardNodes;
262     while (const CFGBlock *B = BackwardWorklist.dequeue())
263       BackwardNodes.push_back(B);
264 
265     EXPECT_EQ(BackwardNodes.size(), ReferenceOrder.size());
266     EXPECT_TRUE(std::equal(ReferenceOrder.begin(), ReferenceOrder.end(),
267                            BackwardNodes.begin()));
268   }
269 }
270 
271 } // namespace
272 } // namespace analysis
273 } // namespace clang
274