summaryrefslogtreecommitdiffstats
path: root/include/clang/Analysis
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
committerdim <dim@FreeBSD.org>2012-08-15 20:02:54 +0000
commit554bcb69c2d785a011a30e7db87a36a87fe7db10 (patch)
tree9abb1a658a297776086f4e0dfa6ca533de02104e /include/clang/Analysis
parentbb67ca86b31f67faee50bd10c3b036d65751745a (diff)
downloadFreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.zip
FreeBSD-src-554bcb69c2d785a011a30e7db87a36a87fe7db10.tar.gz
Vendor import of clang trunk r161861:
http://llvm.org/svn/llvm-project/cfe/trunk@161861
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h65
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h9
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h60
-rw-r--r--include/clang/Analysis/AnalysisContext.h50
-rw-r--r--include/clang/Analysis/CFG.h12
-rw-r--r--include/clang/Analysis/CallGraph.h10
-rw-r--r--include/clang/Analysis/ProgramPoint.h169
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h2
8 files changed, 264 insertions, 113 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 9ec27ce..7f50ee3 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -175,6 +175,7 @@ public:
switch (kind) {
case PrintErrno:
assert(IsPrintf);
+ return false;
case PercentArg:
return false;
default:
@@ -200,7 +201,7 @@ protected:
Kind kind;
};
-class ArgTypeResult {
+class ArgType {
public:
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
AnyCharTy, CStrTy, WCStrTy, WIntTy };
@@ -208,26 +209,26 @@ private:
const Kind K;
QualType T;
const char *Name;
- ArgTypeResult(bool) : K(InvalidTy), Name(0) {}
+ bool Ptr;
public:
- ArgTypeResult(Kind k = UnknownTy) : K(k), Name(0) {}
- ArgTypeResult(Kind k, const char *n) : K(k), Name(n) {}
- ArgTypeResult(QualType t) : K(SpecificTy), T(t), Name(0) {}
- ArgTypeResult(QualType t, const char *n) : K(SpecificTy), T(t), Name(n) {}
- ArgTypeResult(CanQualType t) : K(SpecificTy), T(t), Name(0) {}
-
- static ArgTypeResult Invalid() { return ArgTypeResult(true); }
+ ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {}
+ ArgType(QualType t, const char *n = 0)
+ : K(SpecificTy), T(t), Name(n), Ptr(false) {}
+ ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {}
+ static ArgType Invalid() { return ArgType(InvalidTy); }
bool isValid() const { return K != InvalidTy; }
- const QualType *getSpecificType() const {
- return K == SpecificTy ? &T : 0;
+ /// Create an ArgType which corresponds to the type pointer to A.
+ static ArgType PtrTo(const ArgType& A) {
+ assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
+ ArgType Res = A;
+ Res.Ptr = true;
+ return Res;
}
bool matchesType(ASTContext &C, QualType argTy) const;
- bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
-
QualType getRepresentativeType(ASTContext &C) const;
std::string getRepresentativeTypeName(ASTContext &C) const;
@@ -278,7 +279,7 @@ public:
return length + UsesDotPrefix;
}
- ArgTypeResult getArgType(ASTContext &Ctx) const;
+ ArgType getArgType(ASTContext &Ctx) const;
void toString(raw_ostream &os) const;
@@ -354,6 +355,10 @@ public:
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
bool hasStandardLengthConversionCombination() const;
+
+ /// For a TypedefType QT, if it is a named integer type such as size_t,
+ /// assign the appropriate value to LM and return true.
+ static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
};
} // end analyze_format_string namespace
@@ -387,7 +392,7 @@ public:
}
};
-using analyze_format_string::ArgTypeResult;
+using analyze_format_string::ArgType;
using analyze_format_string::LengthModifier;
using analyze_format_string::OptionalAmount;
using analyze_format_string::OptionalFlag;
@@ -462,7 +467,7 @@ public:
/// will return null if the format specifier does not have
/// a matching data argument or the matching argument matches
/// more than one type.
- ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
+ ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
const OptionalFlag &hasThousandsGrouping() const {
return HasThousandsGrouping;
@@ -516,35 +521,11 @@ public:
}
};
-using analyze_format_string::ArgTypeResult;
+using analyze_format_string::ArgType;
using analyze_format_string::LengthModifier;
using analyze_format_string::OptionalAmount;
using analyze_format_string::OptionalFlag;
-class ScanfArgTypeResult : public ArgTypeResult {
-public:
- enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy };
-private:
- Kind K;
- ArgTypeResult A;
- const char *Name;
- QualType getRepresentativeType(ASTContext &C) const;
-public:
- ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {}
- ScanfArgTypeResult(ArgTypeResult a, const char *n = 0)
- : K(PtrToArgTypeResultTy), A(a), Name(n) {
- assert(A.isValid());
- }
-
- static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); }
-
- bool isValid() const { return K != InvalidTy; }
-
- bool matchesType(ASTContext& C, QualType argTy) const;
-
- std::string getRepresentativeTypeName(ASTContext& C) const;
-};
-
class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
OptionalFlag SuppressAssignment; // '*'
public:
@@ -573,7 +554,7 @@ public:
return CS.consumesDataArgument() && !SuppressAssignment;
}
- ScanfArgTypeResult getArgType(ASTContext &Ctx) const;
+ ArgType getArgType(ASTContext &Ctx) const;
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index 26e258d..742cc04 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -60,7 +60,8 @@ enum AccessKind {
enum LockErrorKind {
LEK_LockedSomeLoopIterations,
LEK_LockedSomePredecessors,
- LEK_LockedAtEndOfFunction
+ LEK_LockedAtEndOfFunction,
+ LEK_NotLockedAtEndOfFunction
};
/// Handler class for thread safety warnings.
@@ -123,11 +124,11 @@ public:
/// Warn when a protected operation occurs while the specific mutex protecting
/// the operation is not locked.
- /// \param LockName -- A StringRef name for the lock expression, to be printed
- /// in the error message.
/// \param D -- The decl for the protected variable or function
/// \param POK -- The kind of protected operation (e.g. variable access)
- /// \param AK -- The kind of access (i.e. read or write) that occurred
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param LK -- The kind of access (i.e. read or write) that occurred
/// \param Loc -- The location of the protected operation.
virtual void handleMutexNotHeld(const NamedDecl *D,
ProtectedOperationKind POK, Name LockName,
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index 4ee6698..45ce4de 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -15,6 +15,8 @@
#ifndef LLVM_CLANG_UNINIT_VALS_H
#define LLVM_CLANG_UNINIT_VALS_H
+#include "llvm/ADT/SmallVector.h"
+
namespace clang {
class AnalysisDeclContext;
@@ -23,15 +25,67 @@ class DeclContext;
class Expr;
class VarDecl;
+/// A use of a variable, which might be uninitialized.
+class UninitUse {
+public:
+ struct Branch {
+ const Stmt *Terminator;
+ unsigned Output;
+ };
+
+private:
+ /// The expression which uses this variable.
+ const Expr *User;
+
+ /// Does this use always see an uninitialized value?
+ bool AlwaysUninit;
+
+ /// This use is always uninitialized if it occurs after any of these branches
+ /// is taken.
+ llvm::SmallVector<Branch, 2> UninitBranches;
+
+public:
+ UninitUse(const Expr *User, bool AlwaysUninit) :
+ User(User), AlwaysUninit(AlwaysUninit) {}
+
+ void addUninitBranch(Branch B) {
+ UninitBranches.push_back(B);
+ }
+
+ /// Get the expression containing the uninitialized use.
+ const Expr *getUser() const { return User; }
+
+ /// The kind of uninitialized use.
+ enum Kind {
+ /// The use might be uninitialized.
+ Maybe,
+ /// The use is uninitialized whenever a certain branch is taken.
+ Sometimes,
+ /// The use is always uninitialized.
+ Always
+ };
+
+ /// Get the kind of uninitialized use.
+ Kind getKind() const {
+ return AlwaysUninit ? Always :
+ !branch_empty() ? Sometimes : Maybe;
+ }
+
+ typedef llvm::SmallVectorImpl<Branch>::const_iterator branch_iterator;
+ /// Branches which inevitably result in the variable being used uninitialized.
+ branch_iterator branch_begin() const { return UninitBranches.begin(); }
+ branch_iterator branch_end() const { return UninitBranches.end(); }
+ bool branch_empty() const { return UninitBranches.empty(); }
+};
+
class UninitVariablesHandler {
public:
UninitVariablesHandler() {}
virtual ~UninitVariablesHandler();
/// Called when the uninitialized variable is used at the given expression.
- virtual void handleUseOfUninitVariable(const Expr *ex,
- const VarDecl *vd,
- bool isAlwaysUninit) {}
+ virtual void handleUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) {}
/// Called when the uninitialized variable analysis detects the
/// idiom 'int x = x'. All other uses of 'x' within the initializer
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 6b6f8ef..46b4e93 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -38,6 +38,7 @@ class PseudoConstantAnalysis;
class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
+class BlockInvocationContext;
class AnalysisDeclContextManager;
class LocationContext;
@@ -73,9 +74,6 @@ class AnalysisDeclContext {
const Decl *D;
- // TranslationUnit is NULL if we don't have multiple translation units.
- idx::TranslationUnit *TU;
-
OwningPtr<CFG> cfg, completeCFG;
OwningPtr<CFGStmtMap> cfgStmtMap;
@@ -98,12 +96,10 @@ class AnalysisDeclContext {
public:
AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *D,
- idx::TranslationUnit *TU);
+ const Decl *D);
AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
const Decl *D,
- idx::TranslationUnit *TU,
const CFG::BuildOptions &BuildOptions);
~AnalysisDeclContext();
@@ -111,8 +107,6 @@ public:
ASTContext &getASTContext() { return D->getASTContext(); }
const Decl *getDecl() const { return D; }
- idx::TranslationUnit *getTranslationUnit() const { return TU; }
-
/// Return the build options used to construct the CFG.
CFG::BuildOptions &getCFGBuildOptions() {
return cfgBuildOptions;
@@ -169,6 +163,11 @@ public:
const Stmt *S,
const CFGBlock *Blk,
unsigned Idx);
+
+ const BlockInvocationContext *
+ getBlockInvocationContext(const LocationContext *parent,
+ const BlockDecl *BD,
+ const void *ContextData);
/// Return the specified analysis object, lazily running the analysis if
/// necessary. Return NULL if the analysis could not run.
@@ -212,10 +211,6 @@ public:
AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
- idx::TranslationUnit *getTranslationUnit() const {
- return Ctx->getTranslationUnit();
- }
-
const LocationContext *getParent() const { return Parent; }
bool isParentOf(const LocationContext *LC) const;
@@ -238,8 +233,6 @@ public:
}
const StackFrameContext *getCurrentStackFrame() const;
- const StackFrameContext *
- getStackFrameForDeclContext(const DeclContext *DC) const;
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
@@ -318,27 +311,32 @@ public:
};
class BlockInvocationContext : public LocationContext {
- // FIXME: Add back context-sensivity (we don't want libAnalysis to know
- // about MemRegion).
const BlockDecl *BD;
+
+ // FIXME: Come up with a more type-safe way to model context-sensitivity.
+ const void *ContextData;
friend class LocationContextManager;
BlockInvocationContext(AnalysisDeclContext *ctx,
const LocationContext *parent,
- const BlockDecl *bd)
- : LocationContext(Block, ctx, parent), BD(bd) {}
+ const BlockDecl *bd, const void *contextData)
+ : LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {}
public:
~BlockInvocationContext() {}
const BlockDecl *getBlockDecl() const { return BD; }
+
+ const void *getContextData() const { return ContextData; }
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
- const LocationContext *parent, const BlockDecl *bd) {
+ const LocationContext *parent, const BlockDecl *bd,
+ const void *contextData) {
ProfileCommon(ID, Block, ctx, parent, bd);
+ ID.AddPointer(contextData);
}
static bool classof(const LocationContext *Ctx) {
@@ -359,6 +357,12 @@ public:
const ScopeContext *getScope(AnalysisDeclContext *ctx,
const LocationContext *parent,
const Stmt *s);
+
+ const BlockInvocationContext *
+ getBlockInvocationContext(AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ const BlockDecl *BD,
+ const void *ContextData);
/// Discard all previously created LocationContext objects.
void clear();
@@ -383,7 +387,7 @@ public:
~AnalysisDeclContextManager();
- AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
+ AnalysisDeclContext *getContext(const Decl *D);
bool getUseUnoptimizedCFG() const {
return !cfgBuildOptions.PruneTriviallyFalseEdges;
@@ -402,9 +406,8 @@ public:
}
// Get the top level stack frame.
- const StackFrameContext *getStackFrame(Decl const *D,
- idx::TranslationUnit *TU) {
- return LocContexts.getStackFrame(getContext(D, TU), 0, 0, 0, 0);
+ const StackFrameContext *getStackFrame(const Decl *D) {
+ return LocContexts.getStackFrame(getContext(D), 0, 0, 0, 0);
}
// Get a stack frame with parent.
@@ -416,7 +419,6 @@ public:
return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
}
-
/// Discard all previously created AnalysisDeclContexts.
void clear();
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 27b22b8..4d087e7 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -21,10 +21,10 @@
#include "llvm/Support/Casting.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/BitVector.h"
#include "clang/AST/Stmt.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceLocation.h"
+#include <bitset>
#include <cassert>
#include <iterator>
@@ -277,6 +277,7 @@ class CFGBlock {
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
typedef ImplTy::iterator reverse_iterator;
typedef ImplTy::const_iterator const_reverse_iterator;
+ typedef ImplTy::const_reference const_reference;
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
@@ -284,8 +285,8 @@ class CFGBlock {
return Impl.insert(I, Cnt, E, C);
}
- CFGElement front() const { return Impl.back(); }
- CFGElement back() const { return Impl.front(); }
+ const_reference front() const { return Impl.back(); }
+ const_reference back() const { return Impl.front(); }
iterator begin() { return Impl.rbegin(); }
iterator end() { return Impl.rend(); }
@@ -558,7 +559,7 @@ public:
//===--------------------------------------------------------------------===//
class BuildOptions {
- llvm::BitVector alwaysAddMask;
+ std::bitset<Stmt::lastStmtConstant> alwaysAddMask;
public:
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
ForcedBlkExprs **forcedBlkExprs;
@@ -583,8 +584,7 @@ public:
}
BuildOptions()
- : alwaysAddMask(Stmt::lastStmtConstant, false)
- ,forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
+ : forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
,AddEHEdges(false)
,AddInitializers(false)
,AddImplicitDtors(false) {}
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
index 9b68073..509de7b 100644
--- a/include/clang/Analysis/CallGraph.h
+++ b/include/clang/Analysis/CallGraph.h
@@ -26,7 +26,7 @@
namespace clang {
class CallGraphNode;
-/// \class The AST-based call graph.
+/// \brief The AST-based call graph.
///
/// The call graph extends itself with the given declarations by implementing
/// the recursive AST visitor, which constructs the graph by visiting the given
@@ -102,7 +102,8 @@ public:
void dump() const;
void viewGraph() const;
- /// Part of recursive declaration visitation.
+ /// Part of recursive declaration visitation. We recursively visit all the
+ /// Declarations to collect the root functions.
bool VisitFunctionDecl(FunctionDecl *FD) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
@@ -121,6 +122,11 @@ public:
return true;
}
+ // We are only collecting the declarations, so do not step into the bodies.
+ bool TraverseStmt(Stmt *S) { return true; }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
private:
/// \brief Add the given declaration to the call graph.
void addNodeForDecl(Decl *D, bool IsGlobal);
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index aa7a33c..5de06cd 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -40,30 +40,36 @@ public:
BlockEntranceKind,
BlockExitKind,
PreStmtKind,
+ PreStmtPurgeDeadSymbolsKind,
+ PostStmtPurgeDeadSymbolsKind,
PostStmtKind,
PreLoadKind,
PostLoadKind,
PreStoreKind,
PostStoreKind,
- PostPurgeDeadSymbolsKind,
PostConditionKind,
PostLValueKind,
+ MinPostStmtKind = PostStmtKind,
+ MaxPostStmtKind = PostLValueKind,
PostInitializerKind,
CallEnterKind,
- CallExitKind,
- MinPostStmtKind = PostStmtKind,
- MaxPostStmtKind = CallExitKind,
+ CallExitBeginKind,
+ CallExitEndKind,
+ PreImplicitCallKind,
+ PostImplicitCallKind,
+ MinImplicitCallKind = PreImplicitCallKind,
+ MaxImplicitCallKind = PostImplicitCallKind,
EpsilonKind};
private:
- llvm::PointerIntPair<const void *, 2, unsigned> Data1;
+ const void *Data1;
llvm::PointerIntPair<const void *, 2, unsigned> Data2;
// The LocationContext could be NULL to allow ProgramPoint to be used in
// context insensitive analysis.
llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
- const ProgramPointTag *Tag;
+ llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
ProgramPoint();
@@ -72,10 +78,10 @@ protected:
Kind k,
const LocationContext *l,
const ProgramPointTag *tag = 0)
- : Data1(P, ((unsigned) k) & 0x3),
- Data2(0, (((unsigned) k) >> 2) & 0x3),
- L(l, (((unsigned) k) >> 4) & 0x3),
- Tag(tag) {
+ : Data1(P),
+ Data2(0, (((unsigned) k) >> 0) & 0x3),
+ L(l, (((unsigned) k) >> 2) & 0x3),
+ Tag(tag, (((unsigned) k) >> 4) & 0x3) {
assert(getKind() == k);
assert(getLocationContext() == l);
assert(getData1() == P);
@@ -86,13 +92,13 @@ protected:
Kind k,
const LocationContext *l,
const ProgramPointTag *tag = 0)
- : Data1(P1, ((unsigned) k) & 0x3),
- Data2(P2, (((unsigned) k) >> 2) & 0x3),
- L(l, (((unsigned) k) >> 4) & 0x3),
- Tag(tag) {}
+ : Data1(P1),
+ Data2(P2, (((unsigned) k) >> 0) & 0x3),
+ L(l, (((unsigned) k) >> 2) & 0x3),
+ Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
protected:
- const void *getData1() const { return Data1.getPointer(); }
+ const void *getData1() const { return Data1; }
const void *getData2() const { return Data2.getPointer(); }
void setData2(const void *d) { Data2.setPointer(d); }
@@ -105,15 +111,23 @@ public:
}
Kind getKind() const {
- unsigned x = L.getInt();
+ unsigned x = Tag.getInt();
x <<= 2;
- x |= Data2.getInt();
+ x |= L.getInt();
x <<= 2;
- x |= Data1.getInt();
+ x |= Data2.getInt();
return (Kind) x;
}
- const ProgramPointTag *getTag() const { return Tag; }
+ /// \brief Is this a program point corresponding to purge/removal of dead
+ /// symbols and bindings.
+ bool isPurgeKind() {
+ Kind K = getKind();
+ return (K == PostStmtPurgeDeadSymbolsKind ||
+ K == PreStmtPurgeDeadSymbolsKind);
+ }
+
+ const ProgramPointTag *getTag() const { return Tag.getPointer(); }
const LocationContext *getLocationContext() const {
return L.getPointer();
@@ -147,7 +161,7 @@ public:
ID.AddPointer(getData1());
ID.AddPointer(getData2());
ID.AddPointer(getLocationContext());
- ID.AddPointer(Tag);
+ ID.AddPointer(getTag());
}
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
@@ -304,7 +318,7 @@ public:
}
};
-/// \class Represents a program point after a store evaluation.
+/// \brief Represents a program point after a store evaluation.
class PostStore : public PostStmt {
public:
/// Construct the post store point.
@@ -340,14 +354,29 @@ public:
}
};
-class PostPurgeDeadSymbols : public PostStmt {
+/// Represents a point after we ran remove dead bindings BEFORE
+/// processing the given statement.
+class PreStmtPurgeDeadSymbols : public StmtPoint {
public:
- PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
+ PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
const ProgramPointTag *tag = 0)
- : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {}
+ : StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { }
static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostPurgeDeadSymbolsKind;
+ return Location->getKind() == PreStmtPurgeDeadSymbolsKind;
+ }
+};
+
+/// Represents a point after we ran remove dead bindings AFTER
+/// processing the given statement.
+class PostStmtPurgeDeadSymbols : public StmtPoint {
+public:
+ PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = 0)
+ : StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { }
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostStmtPurgeDeadSymbolsKind;
}
};
@@ -383,11 +412,60 @@ public:
}
};
-class CallEnter : public StmtPoint {
+/// Represents an implicit call event.
+///
+/// The nearest statement is provided for diagnostic purposes.
+class ImplicitCallPoint : public ProgramPoint {
+public:
+ ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
+ const LocationContext *L, const ProgramPointTag *Tag)
+ : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
+
+ const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
+ SourceLocation getLocation() const {
+ return SourceLocation::getFromPtrEncoding(getData1());
+ }
+
+ static bool classof(const ProgramPoint *Location) {
+ return Location->getKind() >= MinImplicitCallKind &&
+ Location->getKind() <= MaxImplicitCallKind;
+ }
+};
+
+/// Represents a program point just before an implicit call event.
+///
+/// Explicit calls will appear as PreStmt program points.
+class PreImplicitCall : public ImplicitCallPoint {
+public:
+ PreImplicitCall(const Decl *D, SourceLocation Loc,
+ const LocationContext *L, const ProgramPointTag *Tag = 0)
+ : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
+
+ static bool classof(const ProgramPoint *Location) {
+ return Location->getKind() == PreImplicitCallKind;
+ }
+};
+
+/// Represents a program point just after an implicit call event.
+///
+/// Explicit calls will appear as PostStmt program points.
+class PostImplicitCall : public ImplicitCallPoint {
+public:
+ PostImplicitCall(const Decl *D, SourceLocation Loc,
+ const LocationContext *L, const ProgramPointTag *Tag = 0)
+ : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
+
+ static bool classof(const ProgramPoint *Location) {
+ return Location->getKind() == PostImplicitCallKind;
+ }
+};
+
+/// Represents a point when we begin processing an inlined call.
+class CallEnter : public ProgramPoint {
public:
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
const LocationContext *callerCtx)
- : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
+ : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
const Stmt *getCallExpr() const {
return static_cast<const Stmt *>(getData1());
@@ -402,14 +480,41 @@ public:
}
};
-class CallExit : public StmtPoint {
+/// Represents a point when we start the call exit sequence (for inlined call).
+///
+/// The call exit is simulated with a sequence of nodes, which occur between
+/// CallExitBegin and CallExitEnd. The following operations occur between the
+/// two program points:
+/// - CallExitBegin
+/// - Bind the return value
+/// - Run Remove dead bindings (to clean up the dead symbols from the callee).
+/// - CallExitEnd
+class CallExitBegin : public ProgramPoint {
+public:
+ // CallExitBegin uses the callee's location context.
+ CallExitBegin(const StackFrameContext *L)
+ : ProgramPoint(0, CallExitBeginKind, L, 0) {}
+
+ static bool classof(const ProgramPoint *Location) {
+ return Location->getKind() == CallExitBeginKind;
+ }
+};
+
+/// Represents a point when we finish the call exit sequence (for inlined call).
+/// \sa CallExitBegin
+class CallExitEnd : public ProgramPoint {
public:
- // CallExit uses the callee's location context.
- CallExit(const Stmt *S, const LocationContext *L)
- : StmtPoint(S, 0, CallExitKind, L, 0) {}
+ // CallExitEnd uses the caller's location context.
+ CallExitEnd(const StackFrameContext *CalleeCtx,
+ const LocationContext *CallerCtx)
+ : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {}
+
+ const StackFrameContext *getCalleeContext() const {
+ return static_cast<const StackFrameContext *>(getData1());
+ }
static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == CallExitKind;
+ return Location->getKind() == CallExitEndKind;
}
};
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index 97eb287..c510e20 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -69,6 +69,7 @@ public:
DISPATCH_CASE(Field)
DISPATCH_CASE(UsingDirective)
DISPATCH_CASE(Using)
+ DISPATCH_CASE(NamespaceAlias)
default:
llvm_unreachable("Subtype of ScopedDecl not handled.");
}
@@ -90,6 +91,7 @@ public:
DEFAULT_DISPATCH(ObjCCategory)
DEFAULT_DISPATCH(UsingDirective)
DEFAULT_DISPATCH(Using)
+ DEFAULT_DISPATCH(NamespaceAlias)
void VisitCXXRecordDecl(CXXRecordDecl *D) {
static_cast<ImplClass*>(this)->VisitRecordDecl(D);
OpenPOWER on IntegriCloud