aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h13
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h3
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValuesV2.h40
-rw-r--r--include/clang/Analysis/AnalysisContext.h37
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h2
-rw-r--r--include/clang/Analysis/CFG.h409
-rw-r--r--include/clang/Analysis/DomainSpecific/CocoaConventions.h40
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h18
-rw-r--r--include/clang/Analysis/ProgramPoint.h48
-rw-r--r--include/clang/Analysis/Support/BumpVector.h29
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h4
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtVisitor.h5
-rw-r--r--include/clang/Analysis/Visitors/CFGStmtVisitor.h4
13 files changed, 554 insertions, 98 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 280b1260ac26..7cc76a8d471b 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -379,6 +379,7 @@ using analyze_format_string::OptionalAmount;
using analyze_format_string::OptionalFlag;
class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
+ OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
OptionalFlag IsLeftJustified; // '-'
OptionalFlag HasPlusPrefix; // '+'
OptionalFlag HasSpacePrefix; // ' '
@@ -388,8 +389,8 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
public:
PrintfSpecifier() :
FormatSpecifier(/* isPrintf = */ true),
- IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
- HasAlternativeForm("#"), HasLeadingZeroes("0") {}
+ HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"),
+ HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {}
static PrintfSpecifier Parse(const char *beg, const char *end);
@@ -397,6 +398,10 @@ public:
void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
CS = cs;
}
+ void setHasThousandsGrouping(const char *position) {
+ HasThousandsGrouping = true;
+ HasThousandsGrouping.setPosition(position);
+ }
void setIsLeftJustified(const char *position) {
IsLeftJustified = true;
IsLeftJustified.setPosition(position);
@@ -445,6 +450,9 @@ public:
/// more than one type.
ArgTypeResult getArgType(ASTContext &Ctx) const;
+ const OptionalFlag &hasThousandsGrouping() const {
+ return HasThousandsGrouping;
+ }
const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
@@ -465,6 +473,7 @@ public:
bool hasValidLeadingZeros() const;
bool hasValidSpacePrefix() const;
bool hasValidLeftJustified() const;
+ bool hasValidThousandsGroupingPrefix() const;
bool hasValidPrecision() const;
bool hasValidFieldWidth() const;
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index 237fe14aed4f..fbbd2613e7c2 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -55,7 +55,8 @@ struct LiveVariables_ValueTypes {
/// ObserveStmt - A callback invoked right before invoking the
/// liveness transfer function on the given statement.
- virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
+ virtual void ObserveStmt(Stmt* S, const CFGBlock *currentBlock,
+ const AnalysisDataTy& AD,
const ValTy& V) {}
virtual void ObserverKill(DeclRefExpr* DR) {}
diff --git a/include/clang/Analysis/Analyses/UninitializedValuesV2.h b/include/clang/Analysis/Analyses/UninitializedValuesV2.h
new file mode 100644
index 000000000000..c1fe040793e1
--- /dev/null
+++ b/include/clang/Analysis/Analyses/UninitializedValuesV2.h
@@ -0,0 +1,40 @@
+//= UninitializedValuesV2.h - Finding uses of uninitialized values --*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for invoking and reported uninitialized values
+// warnings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNINIT_VALS_H
+#define LLVM_CLANG_UNINIT_VALS_H
+
+namespace clang {
+
+class AnalysisContext;
+class CFG;
+class DeclContext;
+class Expr;
+class VarDecl;
+
+class UninitVariablesHandler {
+public:
+ UninitVariablesHandler() {}
+ virtual ~UninitVariablesHandler();
+
+ virtual void handleUseOfUninitVariable(const Expr *ex,
+ const VarDecl *vd) {}
+};
+
+void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler &handler);
+
+}
+#endif
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 7d4d25f8b0d8..2ecbfdc6bf02 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
@@ -56,15 +57,20 @@ class AnalysisContext {
llvm::BumpPtrAllocator A;
bool UseUnoptimizedCFG;
bool AddEHEdges;
+ bool AddImplicitDtors;
+ bool AddInitializers;
public:
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
bool useUnoptimizedCFG = false,
- bool addehedges = false)
+ bool addehedges = false,
+ bool addImplicitDtors = false,
+ bool addInitializers = false)
: D(d), TU(tu), cfg(0), completeCFG(0),
builtCFG(false), builtCompleteCFG(false),
liveness(0), relaxedLiveness(0), PM(0), PCA(0),
ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG),
- AddEHEdges(addehedges) {}
+ AddEHEdges(addehedges), AddImplicitDtors(addImplicitDtors),
+ AddInitializers(addInitializers) {}
~AnalysisContext();
@@ -80,13 +86,17 @@ public:
bool getAddEHEdges() const { return AddEHEdges; }
bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
+ bool getAddImplicitDtors() const { return AddImplicitDtors; }
+ bool getAddInitializers() const { return AddInitializers; }
Stmt *getBody();
CFG *getCFG();
-
+
/// Return a version of the CFG without any edges pruned.
CFG *getUnoptimizedCFG();
+ void dumpCFG();
+
ParentMap &getParentMap();
PseudoConstantAnalysis *getPseudoConstantAnalysis();
LiveVariables *getLiveVariables();
@@ -106,15 +116,21 @@ class AnalysisContextManager {
typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
ContextMap Contexts;
bool UseUnoptimizedCFG;
+ bool AddImplicitDtors;
+ bool AddInitializers;
public:
- AnalysisContextManager(bool useUnoptimizedCFG = false)
- : UseUnoptimizedCFG(useUnoptimizedCFG) {}
+ AnalysisContextManager(bool useUnoptimizedCFG = false,
+ bool addImplicitDtors = false, bool addInitializers = false)
+ : UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors),
+ AddInitializers(addInitializers) {}
~AnalysisContextManager();
AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
+ bool getAddImplicitDtors() const { return AddImplicitDtors; }
+ bool getAddInitializers() const { return AddInitializers; }
// Discard all previously created AnalysisContexts.
void clear();
@@ -196,9 +212,10 @@ class StackFrameContext : public LocationContext {
friend class LocationContextManager;
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
- const Stmt *s, const CFGBlock *blk, unsigned idx)
- : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
- Index(idx) {}
+ const Stmt *s, const CFGBlock *blk,
+ unsigned idx)
+ : LocationContext(StackFrame, ctx, parent), CallSite(s),
+ Block(blk), Index(idx) {}
public:
~StackFrameContext() {}
@@ -282,8 +299,8 @@ public:
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
- const Stmt *s, const CFGBlock *blk,
- unsigned idx);
+ const Stmt *s,
+ const CFGBlock *blk, unsigned idx);
const ScopeContext *getScope(AnalysisContext *ctx,
const LocationContext *parent,
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index e98a3df472a8..295d0a2133d3 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -15,7 +15,7 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
#define ANALYSISSTART
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index b7a8e1159693..b337d74495c9 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -22,14 +22,21 @@
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceLocation.h"
#include <cassert>
+#include <iterator>
namespace llvm {
class raw_ostream;
}
+
namespace clang {
class Decl;
class Stmt;
class Expr;
+ class FieldDecl;
+ class VarDecl;
+ class CXXCtorInitializer;
+ class CXXBaseSpecifier;
+ class CXXBindTemporaryExpr;
class CFG;
class PrinterHelper;
class LangOptions;
@@ -37,19 +44,203 @@ namespace clang {
/// CFGElement - Represents a top-level expression in a basic block.
class CFGElement {
- llvm::PointerIntPair<Stmt *, 2> Data;
public:
- enum Type { StartScope, EndScope };
- explicit CFGElement() {}
- CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {}
- CFGElement(Stmt *S, Type t) : Data(S, t == StartScope ? 2 : 3) {}
- Stmt *getStmt() const { return Data.getPointer(); }
- bool asLValue() const { return Data.getInt() == 1; }
- bool asStartScope() const { return Data.getInt() == 2; }
- bool asEndScope() const { return Data.getInt() == 3; }
- bool asDtor() const { return Data.getInt() == 4; }
+ enum Kind {
+ // main kind
+ Statement,
+ Initializer,
+ ImplicitDtor,
+ // dtor kind
+ AutomaticObjectDtor,
+ BaseDtor,
+ MemberDtor,
+ TemporaryDtor,
+ DTOR_BEGIN = AutomaticObjectDtor
+ };
+
+protected:
+ // The int bits are used to mark the main kind.
+ llvm::PointerIntPair<void *, 2> Data1;
+ // The int bits are used to mark the dtor kind.
+ llvm::PointerIntPair<void *, 2> Data2;
+
+ CFGElement(void *Ptr, unsigned Int) : Data1(Ptr, Int) {}
+ CFGElement(void *Ptr1, unsigned Int1, void *Ptr2, unsigned Int2)
+ : Data1(Ptr1, Int1), Data2(Ptr2, Int2) {}
+
+public:
+ CFGElement() {}
+
+ Kind getKind() const { return static_cast<Kind>(Data1.getInt()); }
+
+ Kind getDtorKind() const {
+ assert(getKind() == ImplicitDtor);
+ return static_cast<Kind>(Data2.getInt() + DTOR_BEGIN);
+ }
+
+ bool isValid() const { return Data1.getPointer(); }
+
+ operator bool() const { return isValid(); }
+
+ template<class ElemTy> ElemTy getAs() const {
+ if (llvm::isa<ElemTy>(this))
+ return *static_cast<const ElemTy*>(this);
+ return ElemTy();
+ }
+
+ static bool classof(const CFGElement *E) { return true; }
+};
+
+class CFGStmt : public CFGElement {
+public:
+ CFGStmt() {}
+ CFGStmt(Stmt *S) : CFGElement(S, 0) {}
+
+ Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); }
+
operator Stmt*() const { return getStmt(); }
- operator bool() const { return getStmt() != 0; }
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == Statement;
+ }
+};
+
+/// CFGInitializer - Represents C++ base or member initializer from
+/// constructor's initialization list.
+class CFGInitializer : public CFGElement {
+public:
+ CFGInitializer() {}
+ CFGInitializer(CXXCtorInitializer* I)
+ : CFGElement(I, Initializer) {}
+
+ CXXCtorInitializer* getInitializer() const {
+ return static_cast<CXXCtorInitializer*>(Data1.getPointer());
+ }
+ operator CXXCtorInitializer*() const { return getInitializer(); }
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == Initializer;
+ }
+};
+
+/// CFGImplicitDtor - Represents C++ object destructor implicitly generated
+/// by compiler on various occasions.
+class CFGImplicitDtor : public CFGElement {
+protected:
+ CFGImplicitDtor(unsigned K, void* P, void* S)
+ : CFGElement(P, ImplicitDtor, S, K - DTOR_BEGIN) {}
+
+public:
+ CFGImplicitDtor() {}
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == ImplicitDtor;
+ }
+};
+
+/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated
+/// for automatic object or temporary bound to const reference at the point
+/// of leaving its local scope.
+class CFGAutomaticObjDtor: public CFGImplicitDtor {
+public:
+ CFGAutomaticObjDtor() {}
+ CFGAutomaticObjDtor(VarDecl* VD, Stmt* S)
+ : CFGImplicitDtor(AutomaticObjectDtor, VD, S) {}
+
+ VarDecl* getVarDecl() const {
+ return static_cast<VarDecl*>(Data1.getPointer());
+ }
+
+ // Get statement end of which triggered the destructor call.
+ Stmt* getTriggerStmt() const {
+ return static_cast<Stmt*>(Data2.getPointer());
+ }
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == ImplicitDtor &&
+ E->getDtorKind() == AutomaticObjectDtor;
+ }
+};
+
+/// CFGBaseDtor - Represents C++ object destructor implicitly generated for
+/// base object in destructor.
+class CFGBaseDtor : public CFGImplicitDtor {
+public:
+ CFGBaseDtor() {}
+ CFGBaseDtor(const CXXBaseSpecifier *BS)
+ : CFGImplicitDtor(BaseDtor, const_cast<CXXBaseSpecifier*>(BS), NULL) {}
+
+ const CXXBaseSpecifier *getBaseSpecifier() const {
+ return static_cast<const CXXBaseSpecifier*>(Data1.getPointer());
+ }
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == ImplicitDtor && E->getDtorKind() == BaseDtor;
+ }
+};
+
+/// CFGMemberDtor - Represents C++ object destructor implicitly generated for
+/// member object in destructor.
+class CFGMemberDtor : public CFGImplicitDtor {
+public:
+ CFGMemberDtor() {}
+ CFGMemberDtor(FieldDecl *FD)
+ : CFGImplicitDtor(MemberDtor, FD, NULL) {}
+
+ FieldDecl *getFieldDecl() const {
+ return static_cast<FieldDecl*>(Data1.getPointer());
+ }
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == ImplicitDtor && E->getDtorKind() == MemberDtor;
+ }
+};
+
+/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated
+/// at the end of full expression for temporary object.
+class CFGTemporaryDtor : public CFGImplicitDtor {
+public:
+ CFGTemporaryDtor() {}
+ CFGTemporaryDtor(CXXBindTemporaryExpr *E)
+ : CFGImplicitDtor(TemporaryDtor, E, NULL) {}
+
+ CXXBindTemporaryExpr *getBindTemporaryExpr() const {
+ return static_cast<CXXBindTemporaryExpr *>(Data1.getPointer());
+ }
+
+ static bool classof(const CFGElement *E) {
+ return E->getKind() == ImplicitDtor && E->getDtorKind() == TemporaryDtor;
+ }
+};
+
+/// CFGTerminator - Represents CFGBlock terminator statement.
+///
+/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch
+/// in control flow of destructors of temporaries. In this case terminator
+/// statement is the same statement that branches control flow in evaluation
+/// of matching full expression.
+class CFGTerminator {
+ llvm::PointerIntPair<Stmt *, 1> Data;
+public:
+ CFGTerminator() {}
+ CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false)
+ : Data(S, TemporaryDtorsBranch) {}
+
+ Stmt *getStmt() { return Data.getPointer(); }
+ const Stmt *getStmt() const { return Data.getPointer(); }
+
+ bool isTemporaryDtorsBranch() const { return Data.getInt(); }
+
+ operator Stmt *() { return getStmt(); }
+ operator const Stmt *() const { return getStmt(); }
+
+ Stmt *operator->() { return getStmt(); }
+ const Stmt *operator->() const { return getStmt(); }
+
+ Stmt &operator*() { return *getStmt(); }
+ const Stmt &operator*() const { return *getStmt(); }
+
+ operator bool() const { return getStmt(); }
};
/// CFGBlock - Represents a single basic block in a source-level CFG.
@@ -77,11 +268,11 @@ public:
/// &&, || expression that uses result of && or ||, RHS
///
class CFGBlock {
- class StatementList {
+ class ElementList {
typedef BumpVector<CFGElement> ImplTy;
ImplTy Impl;
public:
- StatementList(BumpVectorContext &C) : Impl(C, 4) {}
+ ElementList(BumpVectorContext &C) : Impl(C, 4) {}
typedef std::reverse_iterator<ImplTy::iterator> iterator;
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
@@ -89,6 +280,11 @@ class CFGBlock {
typedef ImplTy::const_iterator const_reverse_iterator;
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
+ reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
+ BumpVectorContext& C) {
+ return Impl.insert(I, Cnt, E, C);
+ }
+
CFGElement front() const { return Impl.back(); }
CFGElement back() const { return Impl.front(); }
@@ -111,7 +307,7 @@ class CFGBlock {
};
/// Stmts - The set of statements in the basic block.
- StatementList Stmts;
+ ElementList Elements;
/// Label - An (optional) label that prefixes the executable
/// statements in the block. When this variable is non-NULL, it is
@@ -121,7 +317,7 @@ class CFGBlock {
/// Terminator - The terminator for a basic block that
/// indicates the type of control-flow that occurs between a block
/// and its successors.
- Stmt *Terminator;
+ CFGTerminator Terminator;
/// LoopTarget - Some blocks are used to represent the "loop edge" to
/// the start of a loop from within the loop body. This Stmt* will be
@@ -140,33 +336,33 @@ class CFGBlock {
public:
explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
- : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
+ : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
~CFGBlock() {}
// Statement iterators
- typedef StatementList::iterator iterator;
- typedef StatementList::const_iterator const_iterator;
- typedef StatementList::reverse_iterator reverse_iterator;
- typedef StatementList::const_reverse_iterator const_reverse_iterator;
+ typedef ElementList::iterator iterator;
+ typedef ElementList::const_iterator const_iterator;
+ typedef ElementList::reverse_iterator reverse_iterator;
+ typedef ElementList::const_reverse_iterator const_reverse_iterator;
- CFGElement front() const { return Stmts.front(); }
- CFGElement back() const { return Stmts.back(); }
+ CFGElement front() const { return Elements.front(); }
+ CFGElement back() const { return Elements.back(); }
- iterator begin() { return Stmts.begin(); }
- iterator end() { return Stmts.end(); }
- const_iterator begin() const { return Stmts.begin(); }
- const_iterator end() const { return Stmts.end(); }
+ iterator begin() { return Elements.begin(); }
+ iterator end() { return Elements.end(); }
+ const_iterator begin() const { return Elements.begin(); }
+ const_iterator end() const { return Elements.end(); }
- reverse_iterator rbegin() { return Stmts.rbegin(); }
- reverse_iterator rend() { return Stmts.rend(); }
- const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
- const_reverse_iterator rend() const { return Stmts.rend(); }
+ reverse_iterator rbegin() { return Elements.rbegin(); }
+ reverse_iterator rend() { return Elements.rend(); }
+ const_reverse_iterator rbegin() const { return Elements.rbegin(); }
+ const_reverse_iterator rend() const { return Elements.rend(); }
- unsigned size() const { return Stmts.size(); }
- bool empty() const { return Stmts.empty(); }
+ unsigned size() const { return Elements.size(); }
+ bool empty() const { return Elements.empty(); }
- CFGElement operator[](size_t i) const { return Stmts[i]; }
+ CFGElement operator[](size_t i) const { return Elements[i]; }
// CFG iterators
typedef AdjacentBlocks::iterator pred_iterator;
@@ -205,14 +401,67 @@ public:
unsigned pred_size() const { return Preds.size(); }
bool pred_empty() const { return Preds.empty(); }
+
+ class FilterOptions {
+ public:
+ FilterOptions() {
+ IgnoreDefaultsWithCoveredEnums = 0;
+ }
+
+ unsigned IgnoreDefaultsWithCoveredEnums : 1;
+ };
+
+ static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
+ const CFGBlock *Dst);
+
+ template <typename IMPL, bool IsPred>
+ class FilteredCFGBlockIterator {
+ private:
+ IMPL I, E;
+ const FilterOptions F;
+ const CFGBlock *From;
+ public:
+ explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
+ const CFGBlock *from,
+ const FilterOptions &f)
+ : I(i), E(e), F(f), From(from) {}
+
+ bool hasMore() const { return I != E; }
+
+ FilteredCFGBlockIterator &operator++() {
+ do { ++I; } while (hasMore() && Filter(*I));
+ return *this;
+ }
+
+ const CFGBlock *operator*() const { return *I; }
+ private:
+ bool Filter(const CFGBlock *To) {
+ return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To);
+ }
+ };
+
+ typedef FilteredCFGBlockIterator<const_pred_iterator, true>
+ filtered_pred_iterator;
+
+ typedef FilteredCFGBlockIterator<const_succ_iterator, false>
+ filtered_succ_iterator;
+
+ filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
+ return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
+ }
+
+ filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const {
+ return filtered_succ_iterator(succ_begin(), succ_end(), this, f);
+ }
+
// Manipulation of block contents
void setTerminator(Stmt* Statement) { Terminator = Statement; }
void setLabel(Stmt* Statement) { Label = Statement; }
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
- Stmt* getTerminator() { return Terminator; }
- const Stmt* getTerminator() const { return Terminator; }
+ CFGTerminator getTerminator() { return Terminator; }
+ const CFGTerminator getTerminator() const { return Terminator; }
Stmt* getTerminatorCondition();
@@ -239,17 +488,39 @@ public:
Succs.push_back(Block, C);
}
- void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) {
- Stmts.push_back(CFGElement(Statement, asLValue), C);
- }
- void StartScope(Stmt* S, BumpVectorContext &C) {
- Stmts.push_back(CFGElement(S, CFGElement::StartScope), C);
+ void appendStmt(Stmt* statement, BumpVectorContext &C) {
+ Elements.push_back(CFGStmt(statement), C);
+ }
+
+ void appendInitializer(CXXCtorInitializer *initializer,
+ BumpVectorContext& C) {
+ Elements.push_back(CFGInitializer(initializer), C);
}
- void EndScope(Stmt* S, BumpVectorContext &C) {
- Stmts.push_back(CFGElement(S, CFGElement::EndScope), C);
+
+ void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
+ Elements.push_back(CFGBaseDtor(BS), C);
}
-};
+ void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) {
+ Elements.push_back(CFGMemberDtor(FD), C);
+ }
+
+ void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) {
+ Elements.push_back(CFGTemporaryDtor(E), C);
+ }
+
+ // Destructors must be inserted 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 beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
+ BumpVectorContext& C) {
+ return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C));
+ }
+ iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) {
+ *I = CFGAutomaticObjDtor(VD, S);
+ return ++I;
+ }
+};
/// CFG - Represents a source-level, intra-procedural CFG that represents the
/// control-flow of a Stmt. The Stmt can represent an entire function body,
@@ -264,13 +535,24 @@ public:
// CFG Construction & Manipulation.
//===--------------------------------------------------------------------===//
+ class BuildOptions {
+ public:
+ bool PruneTriviallyFalseEdges:1;
+ bool AddEHEdges:1;
+ bool AddInitializers:1;
+ bool AddImplicitDtors:1;
+
+ BuildOptions()
+ : PruneTriviallyFalseEdges(true)
+ , AddEHEdges(false)
+ , AddInitializers(false)
+ , AddImplicitDtors(false) {}
+ };
+
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
/// constructed CFG belongs to the caller.
static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C,
- bool pruneTriviallyFalseEdges = true,
- bool AddEHEdges = false,
- bool AddScopes = false /* NOT FULLY IMPLEMENTED.
- NOT READY FOR GENERAL USE. */);
+ BuildOptions BO = BuildOptions());
/// createBlock - Create a new block in the CFG. The CFG owns the block;
/// the caller should not directly free it.
@@ -324,8 +606,10 @@ public:
void VisitBlockStmts(CALLBACK& O) const {
for (const_iterator I=begin(), E=end(); I != E; ++I)
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
- BI != BE; ++BI)
- O(*BI);
+ BI != BE; ++BI) {
+ if (CFGStmt S = BI->getAs<CFGStmt>())
+ O(S);
+ }
}
//===--------------------------------------------------------------------===//
@@ -340,7 +624,10 @@ public:
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
};
- bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
+ bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
+ bool isBlkExpr(const Stmt *S) const {
+ return const_cast<CFG*>(this)->isBlkExpr(S);
+ }
BlkExprNumTy getBlkExprNum(const Stmt* S);
unsigned getNumBlkExprs();
@@ -398,18 +685,22 @@ private:
namespace llvm {
-/// Implement simplify_type for CFGElement, so that we can dyn_cast from
-/// CFGElement to a specific Stmt class.
-template <> struct simplify_type<const ::clang::CFGElement> {
- typedef ::clang::Stmt* SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::CFGElement &Val) {
+/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from
+/// CFGTerminator to a specific Stmt class.
+template <> struct simplify_type<const ::clang::CFGTerminator> {
+ typedef const ::clang::Stmt *SimpleType;
+ static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) {
return Val.getStmt();
}
};
-
-template <> struct simplify_type< ::clang::CFGElement>
- : public simplify_type<const ::clang::CFGElement> {};
-
+
+template <> struct simplify_type< ::clang::CFGTerminator> {
+ typedef ::clang::Stmt *SimpleType;
+ static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) {
+ return const_cast<SimpleType>(Val.getStmt());
+ }
+};
+
// Traits for: CFGBlock
template <> struct GraphTraits< ::clang::CFGBlock* > {
diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
new file mode 100644
index 000000000000..7e6e3815400c
--- /dev/null
+++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
@@ -0,0 +1,40 @@
+//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
+#define LLVM_CLANG_ANALYSIS_DS_COCOA
+
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace ento {
+namespace cocoa {
+
+ enum NamingConvention { NoConvention, CreateRule, InitRule };
+
+ NamingConvention deriveNamingConvention(Selector S, bool ignorePrefix = true);
+
+ static inline bool followsFundamentalRule(Selector S) {
+ return deriveNamingConvention(S) == CreateRule;
+ }
+
+ bool isRefType(QualType RetTy, llvm::StringRef Prefix,
+ llvm::StringRef Name = llvm::StringRef());
+
+ bool isCFObjectRef(QualType T);
+
+ bool isCocoaObjectRef(QualType T);
+
+}}}
+
+#endif
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index 9375db06be72..d75d333db6b6 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -273,8 +273,13 @@ private:
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
dataflow::forward_analysis_tag) {
- for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
- ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
+ TF.setCurrentBlock(B);
+
+ for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
+ CFGElement El = *I;
+ if (CFGStmt S = El.getAs<CFGStmt>())
+ ProcessStmt(S, recordStmtValues, AnalysisDirTag());
+ }
TF.VisitTerminator(const_cast<CFGBlock*>(B));
}
@@ -282,10 +287,15 @@ private:
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
dataflow::backward_analysis_tag) {
+ TF.setCurrentBlock(B);
+
TF.VisitTerminator(const_cast<CFGBlock*>(B));
- for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
- ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
+ for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
+ CFGElement El = *I;
+ if (CFGStmt S = El.getAs<CFGStmt>())
+ ProcessStmt(S, recordStmtValues, AnalysisDirTag());
+ }
}
void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index ba303de7a8da..54cfc3dc0db6 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -17,7 +17,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
-#include "llvm/System/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Casting.h"
@@ -44,6 +44,7 @@ public:
PostPurgeDeadSymbolsKind,
PostStmtCustomKind,
PostLValueKind,
+ PostInitializerKind,
CallEnterKind,
CallExitKind,
MinPostStmtKind = PostStmtKind,
@@ -70,11 +71,12 @@ protected:
protected:
const void* getData1() const { return Data.first; }
const void* getData2() const { return Data.second; }
- const void *getTag() const { return Tag; }
public:
Kind getKind() const { return K; }
+ const void *getTag() const { return Tag; }
+
const LocationContext *getLocationContext() const { return L; }
// For use with DenseMap. This hash is probably slow.
@@ -118,10 +120,12 @@ public:
return B->empty() ? CFGElement() : B->front();
}
- const Stmt *getFirstStmt() const {
- return getFirstElement().getStmt();
+ /// Create a new BlockEntrance object that is the same as the original
+ /// except for using the specified tag value.
+ BlockEntrance withTag(const void *tag) {
+ return BlockEntrance(getBlock(), getLocationContext(), tag);
}
-
+
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == BlockEntranceKind;
}
@@ -136,11 +140,6 @@ public:
return reinterpret_cast<const CFGBlock*>(getData1());
}
- const Stmt* getLastStmt() const {
- const CFGBlock* B = getBlock();
- return B->empty() ? CFGElement() : B->back();
- }
-
const Stmt* getTerminator() const {
return getBlock()->getTerminator();
}
@@ -183,14 +182,15 @@ public:
class PostStmt : public StmtPoint {
protected:
- PostStmt(const Stmt* S, Kind k, const LocationContext *L, const void *tag = 0)
- : StmtPoint(S, NULL, k, L, tag) {}
-
PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
const void *tag =0)
: StmtPoint(S, data, k, L, tag) {}
public:
+ explicit PostStmt(const Stmt* S, Kind k,
+ const LocationContext *L, const void *tag = 0)
+ : StmtPoint(S, NULL, k, L, tag) {}
+
explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0)
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
@@ -313,19 +313,29 @@ public:
}
};
+class PostInitializer : public ProgramPoint {
+public:
+ PostInitializer(const CXXCtorInitializer *I,
+ const LocationContext *L)
+ : ProgramPoint(I, PostInitializerKind, L) {}
+
+ static bool classof(const ProgramPoint *Location) {
+ return Location->getKind() == PostInitializerKind;
+ }
+};
+
class CallEnter : public StmtPoint {
public:
- // L is caller's location context. AC is callee's AnalysisContext.
- CallEnter(const Stmt *S, const AnalysisContext *AC, const LocationContext *L)
- : StmtPoint(S, AC, CallEnterKind, L, 0) {}
+ CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
+ const LocationContext *callerCtx)
+ : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
const Stmt *getCallExpr() const {
return static_cast<const Stmt *>(getData1());
}
- AnalysisContext *getCalleeContext() const {
- return const_cast<AnalysisContext *>(
- static_cast<const AnalysisContext *>(getData2()));
+ const StackFrameContext *getCalleeContext() const {
+ return static_cast<const StackFrameContext *>(getData2());
}
static bool classof(const ProgramPoint *Location) {
diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h
index 7cd481238f81..83532e62babe 100644
--- a/include/clang/Analysis/Support/BumpVector.h
+++ b/include/clang/Analysis/Support/BumpVector.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/PointerIntPair.h"
#include <algorithm>
#include <cstring>
+#include <iterator>
#include <memory>
namespace clang {
@@ -155,7 +156,25 @@ public:
grow(C);
goto Retry;
}
-
+
+ /// insert - Insert some number of copies of element into a position. Return
+ /// iterator to position after last inserted copy.
+ iterator insert(iterator I, size_t Cnt, const_reference E,
+ BumpVectorContext &C) {
+ assert (I >= Begin && I <= End && "Iterator out of bounds.");
+ if (End + Cnt <= Capacity) {
+ Retry:
+ move_range_right(I, End, Cnt);
+ construct_range(I, I + Cnt, E);
+ End += Cnt;
+ return I + Cnt;
+ }
+ ptrdiff_t D = I - Begin;
+ grow(C, size() + Cnt);
+ I = Begin + D;
+ goto Retry;
+ }
+
void reserve(BumpVectorContext &C, unsigned N) {
if (unsigned(Capacity-Begin) < N)
grow(C, N);
@@ -181,6 +200,14 @@ private:
E->~T();
}
}
+
+ void move_range_right(T *S, T *E, size_t D) {
+ for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) {
+ --E;
+ new (I) T(*E);
+ E->~T();
+ }
+ }
};
// Define this out-of-line to dissuade the C++ compiler from inlining it.
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index f20a49a6fcd8..95f4ace76e8c 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -66,6 +66,8 @@ public:
DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl?
DISPATCH_CASE(CXXRecord)
DISPATCH_CASE(Enum)
+ DISPATCH_CASE(UsingDirective)
+ DISPATCH_CASE(Using)
default:
assert(false && "Subtype of ScopedDecl not handled.");
}
@@ -85,6 +87,8 @@ public:
DEFAULT_DISPATCH(ObjCMethod)
DEFAULT_DISPATCH(ObjCProtocol)
DEFAULT_DISPATCH(ObjCCategory)
+ DEFAULT_DISPATCH(UsingDirective)
+ DEFAULT_DISPATCH(Using)
void VisitCXXRecordDecl(CXXRecordDecl *D) {
static_cast<ImplClass*>(this)->VisitRecordDecl(D);
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
index 75a4ac66012e..bb7cf0b97e53 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
@@ -26,6 +26,11 @@ public:
static_cast< ImplClass* >(this)->VisitChildren(S);
}
+ void VisitCompoundStmt(CompoundStmt *S) {
+ // Do nothing. Everything in a CompoundStmt is inlined
+ // into the CFG.
+ }
+
void VisitConditionVariableInit(Stmt *S) {
assert(S == this->getCurrentBlkStmt());
VarDecl *CondVar = 0;
diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
index 6421f185ff7f..d197e69babde 100644
--- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
@@ -80,6 +80,7 @@ public:
DISPATCH_CASE(StmtExpr)
DISPATCH_CASE(ConditionalOperator)
+ DISPATCH_CASE(BinaryConditionalOperator)
DISPATCH_CASE(ObjCForCollectionStmt)
case Stmt::BinaryOperatorClass: {
@@ -102,6 +103,7 @@ public:
DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
+ DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
@@ -155,7 +157,7 @@ public:
}
}
- for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
+ for (Stmt::child_range I = S->children(); I; ++I)
if (*I) static_cast<ImplClass*>(this)->Visit(*I);
}
};