1 //===- unittests/Analysis/CFGTest.cpp - CFG tests -------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "clang/Analysis/CFG.h"
10 #include "CFGBuildResult.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Analysis/Analyses/IntervalPartition.h"
14 #include "clang/Analysis/AnalysisDeclContext.h"
15 #include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
27 // Constructing a CFG for a range-based for over a dependent type fails (but
29 TEST(CFG
, RangeBasedForOverDependentType
) {
30 const char *Code
= "class Foo;\n"
31 "template <typename T>\n"
32 "void f(const T &Range) {\n"
33 " for (const Foo *TheFoo : Range) {\n"
36 EXPECT_EQ(BuildResult::SawFunctionBody
, BuildCFG(Code
).getStatus());
39 TEST(CFG
, StaticInitializerLastCondition
) {
40 const char *Code
= "void f() {\n"
42 " static int j = 3 ;\n"
44 CFG::BuildOptions Options
;
45 Options
.AddStaticInitBranches
= true;
46 Options
.setAllAlwaysAdd();
47 BuildResult B
= BuildCFG(Code
, Options
);
48 EXPECT_EQ(BuildResult::BuiltCFG
, B
.getStatus());
49 EXPECT_EQ(1u, B
.getCFG()->getEntry().succ_size());
50 CFGBlock
*Block
= *B
.getCFG()->getEntry().succ_begin();
51 EXPECT_TRUE(isa
<DeclStmt
>(Block
->getTerminatorStmt()));
52 EXPECT_EQ(nullptr, Block
->getLastCondition());
55 // Constructing a CFG containing a delete expression on a dependent type should
57 TEST(CFG
, DeleteExpressionOnDependentType
) {
58 const char *Code
= "template<class T>\n"
62 EXPECT_EQ(BuildResult::BuiltCFG
, BuildCFG(Code
).getStatus());
65 // Constructing a CFG on a function template with a variable of incomplete type
67 TEST(CFG
, VariableOfIncompleteType
) {
68 const char *Code
= "template<class T> void f() {\n"
72 EXPECT_EQ(BuildResult::BuiltCFG
, BuildCFG(Code
).getStatus());
75 // Constructing a CFG with a dependent base should not crash.
76 TEST(CFG
, DependantBaseAddImplicitDtors
) {
77 const char *Code
= R
"(
84 struct Derived : public Base<T> {
88 CFG::BuildOptions Options
;
89 Options
.AddImplicitDtors
= true;
90 Options
.setAllAlwaysAdd();
91 EXPECT_EQ(BuildResult::BuiltCFG
,
92 BuildCFG(Code
, Options
, ast_matchers::hasName("~Derived<T>"))
97 auto expectLinear
= [](bool IsLinear
, const char *Code
) {
98 BuildResult B
= BuildCFG(Code
);
99 EXPECT_EQ(BuildResult::BuiltCFG
, B
.getStatus());
100 EXPECT_EQ(IsLinear
, B
.getCFG()->isLinear());
103 expectLinear(true, "void foo() {}");
104 expectLinear(true, "void foo() { if (true) return; }");
105 expectLinear(true, "void foo() { if constexpr (false); }");
106 expectLinear(false, "void foo(bool coin) { if (coin) return; }");
107 expectLinear(false, "void foo() { for(;;); }");
108 expectLinear(false, "void foo() { do {} while (true); }");
109 expectLinear(true, "void foo() { do {} while (false); }");
110 expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
113 TEST(CFG
, ElementRefIterator
) {
114 const char *Code
= R
"(void f() {
122 BuildResult B
= BuildCFG(Code
);
123 EXPECT_EQ(BuildResult::BuiltCFG
, B
.getStatus());
124 CFG
*Cfg
= B
.getCFG();
140 CFGBlock
*MainBlock
= *(Cfg
->begin() + 1);
142 constexpr CFGBlock::ref_iterator::difference_type MainBlockSize
= 4;
144 // The rest of this test looks totally insane, but there iterators are
145 // templates under the hood, to it's important to instantiate everything for
148 // Non-reverse, non-const version
150 for (CFGBlock::CFGElementRef ElementRef
: MainBlock
->refs()) {
151 EXPECT_EQ(ElementRef
.getParent(), MainBlock
);
152 EXPECT_EQ(ElementRef
.getIndexInBlock(), Index
);
153 EXPECT_TRUE(ElementRef
->getAs
<CFGStmt
>());
154 EXPECT_TRUE((*ElementRef
).getAs
<CFGStmt
>());
155 EXPECT_EQ(ElementRef
.getParent(), MainBlock
);
158 EXPECT_TRUE(*MainBlock
->ref_begin() < *(MainBlock
->ref_begin() + 1));
159 EXPECT_TRUE(*MainBlock
->ref_begin() == *MainBlock
->ref_begin());
160 EXPECT_FALSE(*MainBlock
->ref_begin() != *MainBlock
->ref_begin());
162 EXPECT_TRUE(MainBlock
->ref_begin() < MainBlock
->ref_begin() + 1);
163 EXPECT_TRUE(MainBlock
->ref_begin() == MainBlock
->ref_begin());
164 EXPECT_FALSE(MainBlock
->ref_begin() != MainBlock
->ref_begin());
165 EXPECT_EQ(MainBlock
->ref_end() - MainBlock
->ref_begin(), MainBlockSize
+ 1);
166 EXPECT_EQ(MainBlock
->ref_end() - MainBlockSize
- 1, MainBlock
->ref_begin());
167 EXPECT_EQ(MainBlock
->ref_begin() + MainBlockSize
+ 1, MainBlock
->ref_end());
168 EXPECT_EQ(MainBlock
->ref_begin()++, MainBlock
->ref_begin());
169 EXPECT_EQ(++(MainBlock
->ref_begin()), MainBlock
->ref_begin() + 1);
171 // Non-reverse, non-const version
172 const CFGBlock
*CMainBlock
= MainBlock
;
174 for (CFGBlock::ConstCFGElementRef ElementRef
: CMainBlock
->refs()) {
175 EXPECT_EQ(ElementRef
.getParent(), CMainBlock
);
176 EXPECT_EQ(ElementRef
.getIndexInBlock(), Index
);
177 EXPECT_TRUE(ElementRef
->getAs
<CFGStmt
>());
178 EXPECT_TRUE((*ElementRef
).getAs
<CFGStmt
>());
179 EXPECT_EQ(ElementRef
.getParent(), MainBlock
);
182 EXPECT_TRUE(*CMainBlock
->ref_begin() < *(CMainBlock
->ref_begin() + 1));
183 EXPECT_TRUE(*CMainBlock
->ref_begin() == *CMainBlock
->ref_begin());
184 EXPECT_FALSE(*CMainBlock
->ref_begin() != *CMainBlock
->ref_begin());
186 EXPECT_TRUE(CMainBlock
->ref_begin() < CMainBlock
->ref_begin() + 1);
187 EXPECT_TRUE(CMainBlock
->ref_begin() == CMainBlock
->ref_begin());
188 EXPECT_FALSE(CMainBlock
->ref_begin() != CMainBlock
->ref_begin());
189 EXPECT_EQ(CMainBlock
->ref_end() - CMainBlock
->ref_begin(), MainBlockSize
+ 1);
190 EXPECT_EQ(CMainBlock
->ref_end() - MainBlockSize
- 1, CMainBlock
->ref_begin());
191 EXPECT_EQ(CMainBlock
->ref_begin() + MainBlockSize
+ 1, CMainBlock
->ref_end());
192 EXPECT_EQ(CMainBlock
->ref_begin()++, CMainBlock
->ref_begin());
193 EXPECT_EQ(++(CMainBlock
->ref_begin()), CMainBlock
->ref_begin() + 1);
195 // Reverse, non-const version
196 Index
= MainBlockSize
;
197 for (CFGBlock::CFGElementRef ElementRef
: MainBlock
->rrefs()) {
198 llvm::errs() << Index
<< '\n';
199 EXPECT_EQ(ElementRef
.getParent(), MainBlock
);
200 EXPECT_EQ(ElementRef
.getIndexInBlock(), Index
);
201 EXPECT_TRUE(ElementRef
->getAs
<CFGStmt
>());
202 EXPECT_TRUE((*ElementRef
).getAs
<CFGStmt
>());
203 EXPECT_EQ(ElementRef
.getParent(), MainBlock
);
206 EXPECT_FALSE(*MainBlock
->rref_begin() < *(MainBlock
->rref_begin() + 1));
207 EXPECT_TRUE(*MainBlock
->rref_begin() == *MainBlock
->rref_begin());
208 EXPECT_FALSE(*MainBlock
->rref_begin() != *MainBlock
->rref_begin());
210 EXPECT_TRUE(MainBlock
->rref_begin() < MainBlock
->rref_begin() + 1);
211 EXPECT_TRUE(MainBlock
->rref_begin() == MainBlock
->rref_begin());
212 EXPECT_FALSE(MainBlock
->rref_begin() != MainBlock
->rref_begin());
213 EXPECT_EQ(MainBlock
->rref_end() - MainBlock
->rref_begin(), MainBlockSize
+ 1);
214 EXPECT_EQ(MainBlock
->rref_end() - MainBlockSize
- 1, MainBlock
->rref_begin());
215 EXPECT_EQ(MainBlock
->rref_begin() + MainBlockSize
+ 1, MainBlock
->rref_end());
216 EXPECT_EQ(MainBlock
->rref_begin()++, MainBlock
->rref_begin());
217 EXPECT_EQ(++(MainBlock
->rref_begin()), MainBlock
->rref_begin() + 1);
219 // Reverse, const version
220 Index
= MainBlockSize
;
221 for (CFGBlock::ConstCFGElementRef ElementRef
: CMainBlock
->rrefs()) {
222 EXPECT_EQ(ElementRef
.getParent(), CMainBlock
);
223 EXPECT_EQ(ElementRef
.getIndexInBlock(), Index
);
224 EXPECT_TRUE(ElementRef
->getAs
<CFGStmt
>());
225 EXPECT_TRUE((*ElementRef
).getAs
<CFGStmt
>());
226 EXPECT_EQ(ElementRef
.getParent(), MainBlock
);
229 EXPECT_FALSE(*CMainBlock
->rref_begin() < *(CMainBlock
->rref_begin() + 1));
230 EXPECT_TRUE(*CMainBlock
->rref_begin() == *CMainBlock
->rref_begin());
231 EXPECT_FALSE(*CMainBlock
->rref_begin() != *CMainBlock
->rref_begin());
233 EXPECT_TRUE(CMainBlock
->rref_begin() < CMainBlock
->rref_begin() + 1);
234 EXPECT_TRUE(CMainBlock
->rref_begin() == CMainBlock
->rref_begin());
235 EXPECT_FALSE(CMainBlock
->rref_begin() != CMainBlock
->rref_begin());
236 EXPECT_EQ(CMainBlock
->rref_end() - CMainBlock
->rref_begin(),
238 EXPECT_EQ(CMainBlock
->rref_end() - MainBlockSize
- 1,
239 CMainBlock
->rref_begin());
240 EXPECT_EQ(CMainBlock
->rref_begin() + MainBlockSize
+ 1,
241 CMainBlock
->rref_end());
242 EXPECT_EQ(CMainBlock
->rref_begin()++, CMainBlock
->rref_begin());
243 EXPECT_EQ(++(CMainBlock
->rref_begin()), CMainBlock
->rref_begin() + 1);
246 TEST(CFG
, Worklists
) {
247 const char *Code
= "int f(bool cond) {\n"
255 BuildResult B
= BuildCFG(Code
);
256 EXPECT_EQ(BuildResult::BuiltCFG
, B
.getStatus());
257 const FunctionDecl
*Func
= B
.getFunc();
258 AnalysisDeclContext
AC(nullptr, Func
);
259 auto *CFG
= AC
.getCFG();
261 std::vector
<const CFGBlock
*> ReferenceOrder
;
262 for (const auto *B
: *AC
.getAnalysis
<PostOrderCFGView
>())
263 ReferenceOrder
.push_back(B
);
266 ForwardDataflowWorklist
ForwardWorklist(*CFG
, AC
);
267 for (const auto *B
: *CFG
)
268 ForwardWorklist
.enqueueBlock(B
);
270 std::vector
<const CFGBlock
*> ForwardNodes
;
271 while (const CFGBlock
*B
= ForwardWorklist
.dequeue())
272 ForwardNodes
.push_back(B
);
274 EXPECT_EQ(ForwardNodes
.size(), ReferenceOrder
.size());
275 EXPECT_TRUE(std::equal(ReferenceOrder
.begin(), ReferenceOrder
.end(),
276 ForwardNodes
.begin()));
280 using ::testing::ElementsAreArray
;
281 std::optional
<WeakTopologicalOrdering
> WTO
= getIntervalWTO(*CFG
);
283 WTOCompare
WCmp(*WTO
);
284 WTODataflowWorklist
WTOWorklist(*CFG
, WCmp
);
285 for (const auto *B
: *CFG
)
286 WTOWorklist
.enqueueBlock(B
);
288 std::vector
<const CFGBlock
*> WTONodes
;
289 while (const CFGBlock
*B
= WTOWorklist
.dequeue())
290 WTONodes
.push_back(B
);
292 EXPECT_THAT(WTONodes
, ElementsAreArray(*WTO
));
295 std::reverse(ReferenceOrder
.begin(), ReferenceOrder
.end());
298 BackwardDataflowWorklist
BackwardWorklist(*CFG
, AC
);
299 for (const auto *B
: *CFG
)
300 BackwardWorklist
.enqueueBlock(B
);
302 std::vector
<const CFGBlock
*> BackwardNodes
;
303 while (const CFGBlock
*B
= BackwardWorklist
.dequeue())
304 BackwardNodes
.push_back(B
);
306 EXPECT_EQ(BackwardNodes
.size(), ReferenceOrder
.size());
307 EXPECT_TRUE(std::equal(ReferenceOrder
.begin(), ReferenceOrder
.end(),
308 BackwardNodes
.begin()));
313 } // namespace analysis