Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp
35269 views
1
//===- AdornedCFG.cpp ---------------------------------------------===//
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
// This file defines an `AdornedCFG` class that is used by dataflow analyses
10
// that run over Control-Flow Graphs (CFGs).
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/Analysis/FlowSensitive/AdornedCFG.h"
15
#include "clang/AST/ASTContext.h"
16
#include "clang/AST/Decl.h"
17
#include "clang/AST/Stmt.h"
18
#include "clang/Analysis/CFG.h"
19
#include "llvm/ADT/BitVector.h"
20
#include "llvm/ADT/DenseMap.h"
21
#include "llvm/Support/Error.h"
22
#include <utility>
23
24
namespace clang {
25
namespace dataflow {
26
27
/// Returns a map from statements to basic blocks that contain them.
28
static llvm::DenseMap<const Stmt *, const CFGBlock *>
29
buildStmtToBasicBlockMap(const CFG &Cfg) {
30
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock;
31
for (const CFGBlock *Block : Cfg) {
32
if (Block == nullptr)
33
continue;
34
35
for (const CFGElement &Element : *Block) {
36
auto Stmt = Element.getAs<CFGStmt>();
37
if (!Stmt)
38
continue;
39
40
StmtToBlock[Stmt->getStmt()] = Block;
41
}
42
}
43
// Some terminator conditions don't appear as a `CFGElement` anywhere else -
44
// for example, this is true if the terminator condition is a `&&` or `||`
45
// operator.
46
// We associate these conditions with the block the terminator appears in,
47
// but only if the condition has not already appeared as a regular
48
// `CFGElement`. (The `insert()` below does nothing if the key already exists
49
// in the map.)
50
for (const CFGBlock *Block : Cfg) {
51
if (Block != nullptr)
52
if (const Stmt *TerminatorCond = Block->getTerminatorCondition())
53
StmtToBlock.insert({TerminatorCond, Block});
54
}
55
// Terminator statements typically don't appear as a `CFGElement` anywhere
56
// else, so we want to associate them with the block that they terminate.
57
// However, there are some important special cases:
58
// - The conditional operator is a type of terminator, but it also appears
59
// as a regular `CFGElement`, and we want to associate it with the block
60
// in which it appears as a `CFGElement`.
61
// - The `&&` and `||` operators are types of terminators, but like the
62
// conditional operator, they can appear as a regular `CFGElement` or
63
// as a terminator condition (see above).
64
// We process terminators last to make sure that we only associate them with
65
// the block they terminate if they haven't previously occurred as a regular
66
// `CFGElement` or as a terminator condition.
67
for (const CFGBlock *Block : Cfg) {
68
if (Block != nullptr)
69
if (const Stmt *TerminatorStmt = Block->getTerminatorStmt())
70
StmtToBlock.insert({TerminatorStmt, Block});
71
}
72
return StmtToBlock;
73
}
74
75
static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
76
llvm::BitVector BlockReachable(Cfg.getNumBlockIDs(), false);
77
78
llvm::SmallVector<const CFGBlock *> BlocksToVisit;
79
BlocksToVisit.push_back(&Cfg.getEntry());
80
while (!BlocksToVisit.empty()) {
81
const CFGBlock *Block = BlocksToVisit.back();
82
BlocksToVisit.pop_back();
83
84
if (BlockReachable[Block->getBlockID()])
85
continue;
86
87
BlockReachable[Block->getBlockID()] = true;
88
89
for (const CFGBlock *Succ : Block->succs())
90
if (Succ)
91
BlocksToVisit.push_back(Succ);
92
}
93
94
return BlockReachable;
95
}
96
97
static llvm::DenseSet<const CFGBlock *>
98
buildContainsExprConsumedInDifferentBlock(
99
const CFG &Cfg,
100
const llvm::DenseMap<const Stmt *, const CFGBlock *> &StmtToBlock) {
101
llvm::DenseSet<const CFGBlock *> Result;
102
103
auto CheckChildExprs = [&Result, &StmtToBlock](const Stmt *S,
104
const CFGBlock *Block) {
105
for (const Stmt *Child : S->children()) {
106
if (!isa_and_nonnull<Expr>(Child))
107
continue;
108
const CFGBlock *ChildBlock = StmtToBlock.lookup(Child);
109
if (ChildBlock != Block)
110
Result.insert(ChildBlock);
111
}
112
};
113
114
for (const CFGBlock *Block : Cfg) {
115
if (Block == nullptr)
116
continue;
117
118
for (const CFGElement &Element : *Block)
119
if (auto S = Element.getAs<CFGStmt>())
120
CheckChildExprs(S->getStmt(), Block);
121
122
if (const Stmt *TerminatorCond = Block->getTerminatorCondition())
123
CheckChildExprs(TerminatorCond, Block);
124
}
125
126
return Result;
127
}
128
129
llvm::Expected<AdornedCFG> AdornedCFG::build(const FunctionDecl &Func) {
130
if (!Func.doesThisDeclarationHaveABody())
131
return llvm::createStringError(
132
std::make_error_code(std::errc::invalid_argument),
133
"Cannot analyze function without a body");
134
135
return build(Func, *Func.getBody(), Func.getASTContext());
136
}
137
138
llvm::Expected<AdornedCFG> AdornedCFG::build(const Decl &D, Stmt &S,
139
ASTContext &C) {
140
if (D.isTemplated())
141
return llvm::createStringError(
142
std::make_error_code(std::errc::invalid_argument),
143
"Cannot analyze templated declarations");
144
145
// The shape of certain elements of the AST can vary depending on the
146
// language. We currently only support C++.
147
if (!C.getLangOpts().CPlusPlus || C.getLangOpts().ObjC)
148
return llvm::createStringError(
149
std::make_error_code(std::errc::invalid_argument),
150
"Can only analyze C++");
151
152
CFG::BuildOptions Options;
153
Options.PruneTriviallyFalseEdges = true;
154
Options.AddImplicitDtors = true;
155
Options.AddTemporaryDtors = true;
156
Options.AddInitializers = true;
157
Options.AddCXXDefaultInitExprInCtors = true;
158
Options.AddLifetime = true;
159
160
// Ensure that all sub-expressions in basic blocks are evaluated.
161
Options.setAllAlwaysAdd();
162
163
auto Cfg = CFG::buildCFG(&D, &S, &C, Options);
164
if (Cfg == nullptr)
165
return llvm::createStringError(
166
std::make_error_code(std::errc::invalid_argument),
167
"CFG::buildCFG failed");
168
169
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock =
170
buildStmtToBasicBlockMap(*Cfg);
171
172
llvm::BitVector BlockReachable = findReachableBlocks(*Cfg);
173
174
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock =
175
buildContainsExprConsumedInDifferentBlock(*Cfg, StmtToBlock);
176
177
return AdornedCFG(D, std::move(Cfg), std::move(StmtToBlock),
178
std::move(BlockReachable),
179
std::move(ContainsExprConsumedInDifferentBlock));
180
}
181
182
} // namespace dataflow
183
} // namespace clang
184
185