Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 42461ee

Browse files
committed
Migrate CFGReachabilityAnalysis out of the IdempotentOperationsChecker and into its own analysis file.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126289 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 283a358 commit 42461ee

File tree

6 files changed

+152
-84
lines changed

6 files changed

+152
-84
lines changed
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//==- CFGReachabilityAnalysis.h - Basic reachability analysis ----*- C++ -*-==//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines a flow-sensitive, (mostly) path-insensitive reachability
11+
// analysis based on Clang's CFGs. Clients can query if a given basic block
12+
// is reachable within the CFG.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef CLANG_ANALYSIS_CFG_REACHABILITY
17+
#define CLANG_ANALYSIS_CFG_REACHABILITY
18+
19+
#include "llvm/ADT/BitVector.h"
20+
#include "llvm/ADT/DenseMap.h"
21+
22+
namespace clang {
23+
24+
class CFG;
25+
class CFGBlock;
26+
27+
// A class that performs reachability queries for CFGBlocks. Several internal
28+
// checks in this checker require reachability information. The requests all
29+
// tend to have a common destination, so we lazily do a predecessor search
30+
// from the destination node and cache the results to prevent work
31+
// duplication.
32+
class CFGReachabilityAnalysis {
33+
typedef llvm::BitVector ReachableSet;
34+
typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
35+
ReachableSet analyzed;
36+
ReachableMap reachable;
37+
public:
38+
CFGReachabilityAnalysis(const CFG &cfg);
39+
40+
/// Returns true if the block 'Dst' can be reached from block 'Src'.
41+
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
42+
43+
private:
44+
void mapReachability(const CFGBlock *Dst);
45+
};
46+
47+
}
48+
49+
#endif

Diff for: include/clang/Analysis/AnalysisContext.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Decl;
2929
class Stmt;
3030
class CFG;
3131
class CFGBlock;
32+
class CFGReachabilityAnalysis;
3233
class CFGStmtMap;
3334
class LiveVariables;
3435
class ParentMap;
@@ -55,6 +56,7 @@ class AnalysisContext {
5556
LiveVariables *relaxedLiveness;
5657
ParentMap *PM;
5758
PseudoConstantAnalysis *PCA;
59+
CFGReachabilityAnalysis *CFA;
5860
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
5961
llvm::BumpPtrAllocator A;
6062
bool UseUnoptimizedCFG;
@@ -69,7 +71,7 @@ class AnalysisContext {
6971
bool addInitializers = false)
7072
: D(d), TU(tu), cfg(0), completeCFG(0), cfgStmtMap(0),
7173
builtCFG(false), builtCompleteCFG(false),
72-
liveness(0), relaxedLiveness(0), PM(0), PCA(0),
74+
liveness(0), relaxedLiveness(0), PM(0), PCA(0), CFA(0),
7375
ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG),
7476
AddEHEdges(addehedges), AddImplicitDtors(addImplicitDtors),
7577
AddInitializers(addInitializers) {}
@@ -96,6 +98,8 @@ class AnalysisContext {
9698

9799
CFGStmtMap *getCFGStmtMap();
98100

101+
CFGReachabilityAnalysis *getCFGReachablityAnalysis();
102+
99103
/// Return a version of the CFG without any edges pruned.
100104
CFG *getUnoptimizedCFG();
101105

Diff for: lib/Analysis/AnalysisContext.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/AST/StmtVisitor.h"
2020
#include "clang/Analysis/Analyses/LiveVariables.h"
2121
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
22+
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
2223
#include "clang/Analysis/AnalysisContext.h"
2324
#include "clang/Analysis/CFG.h"
2425
#include "clang/Analysis/CFGStmtMap.h"
@@ -98,7 +99,18 @@ CFGStmtMap *AnalysisContext::getCFGStmtMap() {
9899

99100
return 0;
100101
}
102+
103+
CFGReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
104+
if (CFA)
105+
return CFA;
106+
107+
if (CFG *c = getCFG()) {
108+
CFA = new CFGReachabilityAnalysis(*c);
109+
return CFA;
110+
}
101111

112+
return 0;
113+
}
102114

103115
void AnalysisContext::dumpCFG() {
104116
getCFG()->dump(getASTContext().getLangOptions());
@@ -365,6 +377,7 @@ AnalysisContext::~AnalysisContext() {
365377
delete relaxedLiveness;
366378
delete PM;
367379
delete PCA;
380+
delete CFA;
368381
delete ReferencedBlockVars;
369382
}
370383

Diff for: lib/Analysis/CFGReachabilityAnalysis.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//==- CFGReachabilityAnalysis.cpp - Basic reachability analysis --*- C++ -*-==//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines a flow-sensitive, (mostly) path-insensitive reachability
11+
// analysis based on Clang's CFGs. Clients can query if a given basic block
12+
// is reachable within the CFG.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "llvm/ADT/SmallVector.h"
17+
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
18+
#include "clang/Analysis/CFG.h"
19+
20+
using namespace clang;
21+
22+
CFGReachabilityAnalysis::CFGReachabilityAnalysis(const CFG &cfg)
23+
: analyzed(cfg.getNumBlockIDs(), false) {}
24+
25+
bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src,
26+
const CFGBlock *Dst) {
27+
28+
const unsigned DstBlockID = Dst->getBlockID();
29+
30+
// If we haven't analyzed the destination node, run the analysis now
31+
if (!analyzed[DstBlockID]) {
32+
mapReachability(Dst);
33+
analyzed[DstBlockID] = true;
34+
}
35+
36+
// Return the cached result
37+
return reachable[DstBlockID][Src->getBlockID()];
38+
}
39+
40+
// Maps reachability to a common node by walking the predecessors of the
41+
// destination node.
42+
void CFGReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
43+
llvm::SmallVector<const CFGBlock *, 11> worklist;
44+
llvm::BitVector visited(analyzed.size());
45+
46+
ReachableSet &DstReachability = reachable[Dst->getBlockID()];
47+
DstReachability.resize(analyzed.size(), false);
48+
49+
// Start searching from the destination node, since we commonly will perform
50+
// multiple queries relating to a destination node.
51+
worklist.push_back(Dst);
52+
bool firstRun = true;
53+
54+
while (!worklist.empty()) {
55+
const CFGBlock *block = worklist.back();
56+
worklist.pop_back();
57+
58+
if (visited[block->getBlockID()])
59+
continue;
60+
visited[block->getBlockID()] = true;
61+
62+
// Update reachability information for this node -> Dst
63+
if (!firstRun) {
64+
// Don't insert Dst -> Dst unless it was a predecessor of itself
65+
DstReachability[block->getBlockID()] = true;
66+
}
67+
else
68+
firstRun = false;
69+
70+
// Add the predecessors to the worklist.
71+
for (CFGBlock::const_pred_iterator i = block->pred_begin(),
72+
e = block->pred_end(); i != e; ++i) {
73+
worklist.push_back(*i);
74+
}
75+
}
76+
}

Diff for: lib/Analysis/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(LLVM_USED_LIBS clangBasic clangAST clangIndex)
33
add_clang_library(clangAnalysis
44
AnalysisContext.cpp
55
CFG.cpp
6+
CFGReachabilityAnalysis.cpp
67
CFGStmtMap.cpp
78
CocoaConventions.cpp
89
FormatString.cpp

Diff for: lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp

+8-83
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "ClangSACheckers.h"
4646
#include "clang/Analysis/CFGStmtMap.h"
4747
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
48+
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
4849
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
4950
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
5051
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -83,9 +84,8 @@ class IdempotentOperationChecker
8384
static bool isUnused(const Expr *E, AnalysisContext *AC);
8485
static bool isTruncationExtensionAssignment(const Expr *LHS,
8586
const Expr *RHS);
86-
bool pathWasCompletelyAnalyzed(const CFG *cfg,
87+
bool pathWasCompletelyAnalyzed(AnalysisContext *AC,
8788
const CFGBlock *CB,
88-
const CFGStmtMap *CBM,
8989
const CoreEngine &CE);
9090
static bool CanVary(const Expr *Ex,
9191
AnalysisContext *AC);
@@ -105,26 +105,6 @@ class IdempotentOperationChecker
105105
typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData>
106106
AssumptionMap;
107107
AssumptionMap hash;
108-
109-
// A class that performs reachability queries for CFGBlocks. Several internal
110-
// checks in this checker require reachability information. The requests all
111-
// tend to have a common destination, so we lazily do a predecessor search
112-
// from the destination node and cache the results to prevent work
113-
// duplication.
114-
class CFGReachabilityAnalysis {
115-
typedef llvm::BitVector ReachableSet;
116-
typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
117-
ReachableSet analyzed;
118-
ReachableMap reachable;
119-
public:
120-
CFGReachabilityAnalysis(const CFG &cfg)
121-
: analyzed(cfg.getNumBlockIDs(), false) {}
122-
123-
inline bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
124-
private:
125-
void MapReachability(const CFGBlock *Dst);
126-
};
127-
llvm::OwningPtr<CFGReachabilityAnalysis> CRA;
128108
};
129109
}
130110

@@ -397,11 +377,9 @@ void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
397377
// If the analyzer did not finish, check to see if we can still emit this
398378
// warning
399379
if (Eng.hasWorkRemaining()) {
400-
const CFGStmtMap *CBM = AC->getCFGStmtMap();
401-
402380
// If we can trace back
403-
if (!pathWasCompletelyAnalyzed(AC->getCFG(),
404-
CBM->getBlock(B), CBM,
381+
if (!pathWasCompletelyAnalyzed(AC,
382+
AC->getCFGStmtMap()->getBlock(B),
405383
Eng.getCoreEngine()))
406384
continue;
407385
}
@@ -561,13 +539,11 @@ bool IdempotentOperationChecker::isTruncationExtensionAssignment(
561539
// Returns false if a path to this block was not completely analyzed, or true
562540
// otherwise.
563541
bool
564-
IdempotentOperationChecker::pathWasCompletelyAnalyzed(const CFG *cfg,
542+
IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
565543
const CFGBlock *CB,
566-
const CFGStmtMap *CBM,
567544
const CoreEngine &CE) {
568545

569-
if (!CRA.get())
570-
CRA.reset(new CFGReachabilityAnalysis(*cfg));
546+
CFGReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
571547

572548
// Test for reachability from any aborted blocks to this block
573549
typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
@@ -618,14 +594,14 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(const CFG *cfg,
618594
return CRA.isReachable(B, TargetBlock);
619595
}
620596
};
621-
VisitWL visitWL(CBM, CB, *CRA.get());
597+
VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA);
622598
// Were there any items in the worklist that could potentially reach
623599
// this block?
624600
if (CE.getWorkList()->visitItemsInWorkList(visitWL))
625601
return false;
626602

627603
// Verify that this block is reachable from the entry block
628-
if (!CRA->isReachable(&cfg->getEntry(), CB))
604+
if (!CRA->isReachable(&AC->getCFG()->getEntry(), CB))
629605
return false;
630606

631607
// If we get to this point, there is no connection to the entry block or an
@@ -763,57 +739,6 @@ bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) {
763739
return false;
764740
}
765741

766-
bool IdempotentOperationChecker::CFGReachabilityAnalysis::isReachable(
767-
const CFGBlock *Src,
768-
const CFGBlock *Dst) {
769-
const unsigned DstBlockID = Dst->getBlockID();
770-
771-
// If we haven't analyzed the destination node, run the analysis now
772-
if (!analyzed[DstBlockID]) {
773-
MapReachability(Dst);
774-
analyzed[DstBlockID] = true;
775-
}
776-
777-
// Return the cached result
778-
return reachable[DstBlockID][Src->getBlockID()];
779-
}
780742

781-
// Maps reachability to a common node by walking the predecessors of the
782-
// destination node.
783-
void IdempotentOperationChecker::CFGReachabilityAnalysis::MapReachability(
784-
const CFGBlock *Dst) {
785743

786-
llvm::SmallVector<const CFGBlock *, 11> worklist;
787-
llvm::BitVector visited(analyzed.size());
788-
789-
ReachableSet &DstReachability = reachable[Dst->getBlockID()];
790-
DstReachability.resize(analyzed.size(), false);
791-
792-
// Start searching from the destination node, since we commonly will perform
793-
// multiple queries relating to a destination node.
794-
worklist.push_back(Dst);
795-
bool firstRun = true;
796-
797-
while (!worklist.empty()) {
798-
const CFGBlock *block = worklist.back();
799-
worklist.pop_back();
800-
801-
if (visited[block->getBlockID()])
802-
continue;
803-
visited[block->getBlockID()] = true;
804-
805-
// Update reachability information for this node -> Dst
806-
if (!firstRun) {
807-
// Don't insert Dst -> Dst unless it was a predecessor of itself
808-
DstReachability[block->getBlockID()] = true;
809-
}
810-
else
811-
firstRun = false;
812744

813-
// Add the predecessors to the worklist.
814-
for (CFGBlock::const_pred_iterator i = block->pred_begin(),
815-
e = block->pred_end(); i != e; ++i) {
816-
worklist.push_back(*i);
817-
}
818-
}
819-
}

0 commit comments

Comments
 (0)