Skip to content

Commit

Permalink
[analyzer] Add scope information to CFG
Browse files Browse the repository at this point in the history
This patch adds two new CFG elements CFGScopeBegin and CFGScopeEnd that indicate
when a local scope begins and ends respectively. We use first VarDecl declared
in a scope to uniquely identify it and add CFGScopeBegin and CFGScopeEnd elements
into corresponding basic blocks.

Differential Revision: https://reviews.llvm.org/D16403

llvm-svn: 327258
  • Loading branch information
chefmax7 committed Mar 12, 2018
1 parent 11a6db3 commit debca45
Show file tree
Hide file tree
Showing 12 changed files with 1,437 additions and 10 deletions.
4 changes: 3 additions & 1 deletion clang/include/clang/Analysis/AnalysisDeclContext.h
Expand Up @@ -435,7 +435,9 @@ class AnalysisDeclContextManager {
bool addImplicitDtors = false,
bool addInitializers = false,
bool addTemporaryDtors = false,
bool addLifetime = false, bool addLoopExit = false,
bool addLifetime = false,
bool addLoopExit = false,
bool addScopes = false,
bool synthesizeBodies = false,
bool addStaticInitBranches = false,
bool addCXXNewAllocator = true,
Expand Down
83 changes: 83 additions & 0 deletions clang/include/clang/Analysis/CFG.h
Expand Up @@ -57,6 +57,8 @@ class CFGElement {
enum Kind {
// main kind
Initializer,
ScopeBegin,
ScopeEnd,
NewAllocator,
LifetimeEnds,
LoopExit,
Expand Down Expand Up @@ -260,6 +262,55 @@ class CFGLifetimeEnds : public CFGElement {
}
};

/// Represents beginning of a scope implicitly generated
/// by the compiler on encountering a CompoundStmt
class CFGScopeBegin : public CFGElement {
public:
CFGScopeBegin() {}
CFGScopeBegin(const VarDecl *VD, const Stmt *S)
: CFGElement(ScopeBegin, VD, S) {}

// Get statement that triggered a new scope.
const Stmt *getTriggerStmt() const {
return static_cast<Stmt*>(Data2.getPointer());
}

// Get VD that triggered a new scope.
const VarDecl *getVarDecl() const {
return static_cast<VarDecl *>(Data1.getPointer());
}

private:
friend class CFGElement;
static bool isKind(const CFGElement &E) {
Kind kind = E.getKind();
return kind == ScopeBegin;
}
};

/// Represents end of a scope implicitly generated by
/// the compiler after the last Stmt in a CompoundStmt's body
class CFGScopeEnd : public CFGElement {
public:
CFGScopeEnd() {}
CFGScopeEnd(const VarDecl *VD, const Stmt *S) : CFGElement(ScopeEnd, VD, S) {}

const VarDecl *getVarDecl() const {
return static_cast<VarDecl *>(Data1.getPointer());
}

const Stmt *getTriggerStmt() const {
return static_cast<Stmt *>(Data2.getPointer());
}

private:
friend class CFGElement;
static bool isKind(const CFGElement &E) {
Kind kind = E.getKind();
return kind == ScopeEnd;
}
};

/// CFGImplicitDtor - Represents C++ object destructor implicitly generated
/// by compiler on various occasions.
class CFGImplicitDtor : public CFGElement {
Expand Down Expand Up @@ -799,6 +850,24 @@ class CFGBlock {
Elements.push_back(CFGNewAllocator(NE), C);
}

void appendScopeBegin(const VarDecl *VD, const Stmt *S,
BumpVectorContext &C) {
Elements.push_back(CFGScopeBegin(VD, S), C);
}

void prependScopeBegin(const VarDecl *VD, const Stmt *S,
BumpVectorContext &C) {
Elements.insert(Elements.rbegin(), 1, CFGScopeBegin(VD, S), C);
}

void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
Elements.push_back(CFGScopeEnd(VD, S), C);
}

void prependScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
Elements.insert(Elements.rbegin(), 1, CFGScopeEnd(VD, S), C);
}

void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
Elements.push_back(CFGBaseDtor(BS), C);
}
Expand Down Expand Up @@ -852,6 +921,19 @@ class CFGBlock {
*I = CFGLifetimeEnds(VD, S);
return ++I;
}

// Scope leaving must be performed in reversed order. So insertion is in two
// steps. First we prepare space for some number of elements, then we insert
// the elements beginning at the last position in prepared space.
iterator beginScopeEndInsert(iterator I, size_t Cnt, BumpVectorContext &C) {
return iterator(
Elements.insert(I.base(), Cnt, CFGScopeEnd(nullptr, nullptr), C));
}
iterator insertScopeEnd(iterator I, VarDecl *VD, Stmt *S) {
*I = CFGScopeEnd(VD, S);
return ++I;
}

};

/// \brief CFGCallback defines methods that should be called when a logical
Expand Down Expand Up @@ -894,6 +976,7 @@ class CFG {
bool AddLifetime = false;
bool AddLoopExit = false;
bool AddTemporaryDtors = false;
bool AddScopes = false;
bool AddStaticInitBranches = false;
bool AddCXXNewAllocator = false;
bool AddCXXDefaultInitExprInCtors = false;
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
Expand Up @@ -240,6 +240,9 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
/// \sa mayInlineCXXStandardLibrary
Optional<bool> InlineCXXStandardLibrary;

/// \sa includeScopesInCFG
Optional<bool> IncludeScopesInCFG;

/// \sa mayInlineTemplateFunctions
Optional<bool> InlineTemplateFunctions;

Expand Down Expand Up @@ -481,6 +484,12 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
/// which accepts the values "true" and "false".
bool includeRichConstructorsInCFG();

/// Returns whether or not scope information should be included in the CFG.
///
/// This is controlled by the 'cfg-scope-info' config option, which accepts
/// the values "true" and "false".
bool includeScopesInCFG();

/// Returns whether or not C++ standard library functions may be considered
/// for inlining.
///
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Analysis/AnalysisDeclContext.cpp
Expand Up @@ -66,9 +66,9 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
AnalysisDeclContextManager::AnalysisDeclContextManager(
ASTContext &ASTCtx, bool useUnoptimizedCFG, bool addImplicitDtors,
bool addInitializers, bool addTemporaryDtors, bool addLifetime,
bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch,
bool addCXXNewAllocator, bool addRichCXXConstructors,
CodeInjector *injector)
bool addLoopExit, bool addScopes, bool synthesizeBodies,
bool addStaticInitBranch, bool addCXXNewAllocator,
bool addRichCXXConstructors, CodeInjector *injector)
: Injector(injector), FunctionBodyFarm(ASTCtx, injector),
SynthesizeBodies(synthesizeBodies) {
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
Expand All @@ -77,6 +77,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
cfgBuildOptions.AddLifetime = addLifetime;
cfgBuildOptions.AddLoopExit = addLoopExit;
cfgBuildOptions.AddScopes = addScopes;
cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
cfgBuildOptions.AddRichCXXConstructors = addRichCXXConstructors;
Expand Down

0 comments on commit debca45

Please sign in to comment.