Prototype (pre-alpha) implementation of CFRef checker.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48272 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Analysis/CFRefCount.cpp b/Analysis/CFRefCount.cpp
index ea9c8bf..a1f63b1 100644
--- a/Analysis/CFRefCount.cpp
+++ b/Analysis/CFRefCount.cpp
@@ -86,6 +86,10 @@
return (*Args)[idx];
}
+ RetEffect getRet() const {
+ return Ret;
+ }
+
typedef ArgEffects::const_iterator arg_iterator;
arg_iterator begin_args() const { return Args->begin(); }
@@ -113,12 +117,24 @@
llvm::BumpPtrAllocator BPAlloc;
ArgEffects ScratchArgs;
+
+
+ ArgEffects* getArgEffects();
+ CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain);
+
+ CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
+
+ CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT);
+ CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT);
+
+ CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
+
public:
CFRefSummaryManager() {}
~CFRefSummaryManager();
- CFRefSummary* getSummary(FunctionDecl* FD);
+ CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
};
} // end anonymous namespace
@@ -137,7 +153,59 @@
I->getValue().~ArgEffects();
}
-CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
+ArgEffects* CFRefSummaryManager::getArgEffects() {
+
+ assert (!ScratchArgs.empty());
+
+ llvm::FoldingSetNodeID profile;
+ profile.Add(ScratchArgs);
+ void* InsertPos;
+
+ llvm::FoldingSetNodeWrapper<ArgEffects>* E =
+ AESet.FindNodeOrInsertPos(profile, InsertPos);
+
+ if (E) {
+ ScratchArgs.clear();
+ return &E->getValue();
+ }
+
+ E = (llvm::FoldingSetNodeWrapper<ArgEffects>*)
+ BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
+
+ new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
+ AESet.InsertNode(E, InsertPos);
+
+ ScratchArgs.clear();
+ return &E->getValue();
+}
+
+CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
+ RetEffect RE) {
+
+ llvm::FoldingSetNodeID profile;
+ CFRefSummary::Profile(profile, AE, RE);
+ void* InsertPos;
+
+ CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
+
+ if (Summ)
+ return Summ;
+
+ Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
+ new (Summ) CFRefSummary(AE, RE);
+ SummarySet.InsertNode(Summ, InsertPos);
+
+ return Summ;
+}
+
+
+CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
+ ASTContext& Ctx) {
+
+ SourceLocation Loc = FD->getLocation();
+
+ if (!Loc.isFileID())
+ return NULL;
{ // Look into our cache of summaries to see if we have already computed
// a summary for this FunctionDecl.
@@ -148,12 +216,169 @@
return I->second;
}
- //
+#if 0
+ SourceManager& SrcMgr = Ctx.getSourceManager();
+ unsigned fid = Loc.getFileID();
+ const FileEntry* FE = SrcMgr.getFileEntryForID(fid);
+ if (!FE)
+ return NULL;
+
+ const char* DirName = FE->getDir()->getName();
+ assert (DirName);
+ assert (strlen(DirName) > 0);
+
+ if (!strstr(DirName, "CoreFoundation")) {
+ SummaryMap[FD] = NULL;
+ return NULL;
+ }
+#endif
+
+ const char* FName = FD->getIdentifier()->getName();
+
+ if (FName[0] == 'C' && FName[1] == 'F') {
+ CFRefSummary* S = getCFSummary(FD, FName);
+ SummaryMap[FD] = S;
+ return S;
+ }
return NULL;
}
+CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
+ const char* FName) {
+
+ // For now, only generate summaries for functions that have a prototype.
+
+ FunctionTypeProto* FT =
+ dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
+
+ if (!FT)
+ return NULL;
+
+ FName += 2;
+
+ if (strcmp(FName, "Retain") == 0)
+ return getCannedCFSummary(FT, true);
+
+ if (strcmp(FName, "Release") == 0)
+ return getCannedCFSummary(FT, false);
+
+ assert (ScratchArgs.empty());
+ bool usesCreateRule = false;
+
+ if (strstr(FName, "Create"))
+ usesCreateRule = true;
+
+ if (!usesCreateRule && strstr(FName, "Copy"))
+ usesCreateRule = true;
+
+ if (usesCreateRule)
+ return getCFSummaryCreateRule(FT);
+
+ if (strstr(FName, "Get"))
+ return getCFSummaryGetRule(FT);
+
+ return NULL;
+}
+
+CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT,
+ bool isRetain) {
+
+ if (FT->getNumArgs() != 1)
+ return NULL;
+
+ TypedefType* ArgT = dyn_cast<TypedefType>(FT->getArgType(0).getTypePtr());
+
+ if (!ArgT)
+ return NULL;
+
+ // For CFRetain/CFRelease, the first (and only) argument is of type
+ // "CFTypeRef".
+
+ const char* TDName = ArgT->getDecl()->getIdentifier()->getName();
+ assert (TDName);
+
+ if (strcmp("CFTypeRef", TDName) == 0)
+ return NULL;
+
+ if (!ArgT->isPointerType())
+ return NULL;
+
+ // Check the return type. It should also be "CFTypeRef".
+
+ QualType RetTy = FT->getResultType();
+
+ if (RetTy.getTypePtr() != ArgT)
+ return NULL;
+
+ // The function's interface checks out. Generate a canned summary.
+
+ assert (ScratchArgs.empty());
+ ScratchArgs.push_back(isRetain ? IncRef : DecRef);
+
+ return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
+}
+
+static bool isCFRefType(QualType T) {
+
+ if (!T->isPointerType())
+ return false;
+
+ // Check the typedef for the name "CF" and the substring "Ref".
+
+ TypedefType* TD = dyn_cast<TypedefType>(T.getTypePtr());
+
+ if (!TD)
+ return false;
+
+ const char* TDName = TD->getDecl()->getIdentifier()->getName();
+ assert (TDName);
+
+ if (TDName[0] != 'C' || TDName[1] != 'F')
+ return false;
+
+ if (strstr(TDName, "Ref") == 0)
+ return false;
+
+ return true;
+}
+
+
+CFRefSummary*
+CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
+
+ if (!isCFRefType(FT->getResultType()))
+ return NULL;
+
+ assert (ScratchArgs.empty());
+
+ // FIXME: Add special-cases for functions that retain/release. For now
+ // just handle the default case.
+
+ for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
+ ScratchArgs.push_back(DoNothing);
+
+ return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
+}
+
+CFRefSummary*
+CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
+
+ if (!isCFRefType(FT->getResultType()))
+ return NULL;
+
+ assert (ScratchArgs.empty());
+
+ // FIXME: Add special-cases for functions that retain/release. For now
+ // just handle the default case.
+
+ for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
+ ScratchArgs.push_back(DoNothing);
+
+ return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
+}
+
//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//
@@ -246,8 +471,8 @@
// Instance variables.
CFRefSummaryManager Summaries;
- RefBFactoryTy RefBFactory;
-
+ RefBFactoryTy RefBFactory;
+
UseAfterReleasesTy UseAfterReleases;
ReleasesNotOwnedTy ReleasesNotOwned;
@@ -282,9 +507,8 @@
// Calls.
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
- ValueStateManager& StateMgr,
+ GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
- BasicValueFactory& BasicVals,
CallExpr* CE, LVal L,
ExplodedNode<ValueState>* Pred);
};
@@ -307,11 +531,12 @@
}
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
- ValueStateManager& StateMgr,
- GRStmtNodeBuilder<ValueState>& Builder,
- BasicValueFactory& BasicVals,
- CallExpr* CE, LVal L,
- ExplodedNode<ValueState>* Pred) {
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<ValueState>& Builder,
+ CallExpr* CE, LVal L,
+ ExplodedNode<ValueState>* Pred) {
+
+ ValueStateManager& StateMgr = Engine.getStateManager();
// FIXME: Support calls to things other than lval::FuncVal. At the very
// least we should stop tracking ref-state for ref-counted objects passed
@@ -323,7 +548,7 @@
lval::FuncVal FV = cast<lval::FuncVal>(L);
FunctionDecl* FD = FV.getDecl();
- CFRefSummary* Summ = Summaries.getSummary(FD);
+ CFRefSummary* Summ = Summaries.getSummary(FD, Engine.getContext());
// Get the state.
@@ -355,35 +580,36 @@
if (isa<LVal>(V))
StateMgr.Unbind(StVals, cast<LVal>(V));
- }
+ }
+
+ St = StateMgr.getPersistentState(StVals);
+ Builder.Nodify(Dst, CE, Pred, St);
+ return;
}
- else {
+
+ // This function has a summary. Evaluate the effect of the arguments.
+
+ unsigned idx = 0;
+
+ for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
+ I!=E; ++I, ++idx) {
- // This function has a summary. Evaluate the effect of the arguments.
+ RVal V = StateMgr.GetRVal(St, *I);
- unsigned idx = 0;
-
- for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end();
- I!=E; ++I, ++idx) {
-
- RVal V = StateMgr.GetRVal(St, *I);
-
- if (isa<lval::SymbolVal>(V)) {
- SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
- RefBindings B = GetRefBindings(StVals);
+ if (isa<lval::SymbolVal>(V)) {
+ SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
+ RefBindings B = GetRefBindings(StVals);
- if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
- B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
- SetRefBindings(StVals, B);
- if (hasError) break;
- }
+ if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
+ B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
+ SetRefBindings(StVals, B);
+ if (hasError) break;
}
- }
- }
-
- St = StateMgr.getPersistentState(StVals);
-
+ }
+ }
+
if (hasError) {
+ St = StateMgr.getPersistentState(StVals);
GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
if (N) {
@@ -399,10 +625,61 @@
ReleasesNotOwned.insert(N);
break;
}
- }
+ }
+
+ return;
}
- else
- Builder.Nodify(Dst, CE, Pred, St);
+
+ // Finally, consult the summary for the return value.
+
+ RetEffect RE = Summ->getRet();
+ St = StateMgr.getPersistentState(StVals);
+
+
+ switch (RE.getKind()) {
+ default:
+ assert (false && "Unhandled RetEffect."); break;
+
+ case RetEffect::Alias: {
+ unsigned idx = RE.getValue();
+ assert (idx < CE->getNumArgs());
+ RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
+ St = StateMgr.SetRVal(St, CE, V, Engine.getCFG().isBlkExpr(CE), false);
+ break;
+ }
+
+ case RetEffect::OwnedSymbol: {
+ unsigned Count = Builder.getCurrentBlockCount();
+ SymbolID Sym = Engine.getSymbolManager().getCallRetValSymbol(CE, Count);
+
+ ValueState StImpl = *St;
+ RefBindings B = GetRefBindings(StImpl);
+ SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1)));
+
+ St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
+ CE, lval::SymbolVal(Sym),
+ Engine.getCFG().isBlkExpr(CE), false);
+
+ break;
+ }
+
+ case RetEffect::NotOwnedSymbol: {
+ unsigned Count = Builder.getCurrentBlockCount();
+ SymbolID Sym = Engine.getSymbolManager().getCallRetValSymbol(CE, Count);
+
+ ValueState StImpl = *St;
+ RefBindings B = GetRefBindings(StImpl);
+ SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
+
+ St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
+ CE, lval::SymbolVal(Sym),
+ Engine.getCFG().isBlkExpr(CE), false);
+
+ break;
+ }
+ }
+
+ Builder.Nodify(Dst, CE, Pred, St);
}
@@ -418,6 +695,12 @@
assert (false && "Unhandled CFRef transition.");
case DoNothing:
+ if (V.getKind() == RefVal::Released) {
+ V = RefVal::makeUseAfterRelease();
+ hasError = V.getKind();
+ break;
+ }
+
return B;
case IncRef:
diff --git a/Analysis/GRSimpleVals.cpp b/Analysis/GRSimpleVals.cpp
index ae06917..16cd674 100644
--- a/Analysis/GRSimpleVals.cpp
+++ b/Analysis/GRSimpleVals.cpp
@@ -95,13 +95,13 @@
if (Diag.hasErrorOccurred())
return 0;
- GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
- GRExprEngine* CheckerState = &Engine.getCheckerState();
+ GRCoreEngine<GRExprEngine> Eng(cfg, FD, Ctx);
+ GRExprEngine* CheckerState = &Eng.getCheckerState();
GRSimpleVals GRSV;
CheckerState->setTransferFunctions(GRSV);
// Execute the worklist algorithm.
- Engine.ExecuteWorkList(50000);
+ Eng.ExecuteWorkList(50000);
SourceManager& SrcMgr = Ctx.getSourceManager();
@@ -144,7 +144,7 @@
if (Visualize) CheckerState->ViewGraph(TrimGraph);
#endif
- return Engine.getGraph().size();
+ return Eng.getGraph().size();
}
} // end clang namespace
@@ -153,14 +153,16 @@
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
-RVal GRSimpleVals::EvalCast(BasicValueFactory& BasicVals, NonLVal X, QualType T) {
+RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLVal X, QualType T) {
if (!isa<nonlval::ConcreteInt>(X))
return UnknownVal();
+
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
llvm::APSInt V = cast<nonlval::ConcreteInt>(X).getValue();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
- V.extOrTrunc(BasicVals.getContext().getTypeSize(T));
+ V.extOrTrunc(Eng.getContext().getTypeSize(T));
if (T->isPointerType())
return lval::ConcreteInt(BasicVals.getValue(V));
@@ -170,7 +172,7 @@
// Casts.
-RVal GRSimpleVals::EvalCast(BasicValueFactory& BasicVals, LVal X, QualType T) {
+RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, LVal X, QualType T) {
if (T->isPointerType() || T->isReferenceType())
return X;
@@ -180,33 +182,35 @@
if (!isa<lval::ConcreteInt>(X))
return UnknownVal();
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+
llvm::APSInt V = cast<lval::ConcreteInt>(X).getValue();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
- V.extOrTrunc(BasicVals.getContext().getTypeSize(T));
+ V.extOrTrunc(Eng.getContext().getTypeSize(T));
return nonlval::ConcreteInt(BasicVals.getValue(V));
}
// Unary operators.
-RVal GRSimpleVals::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U, NonLVal X){
+RVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLVal X){
switch (X.getSubKind()) {
case nonlval::ConcreteIntKind:
- return cast<nonlval::ConcreteInt>(X).EvalMinus(BasicVals, U);
+ return cast<nonlval::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
default:
return UnknownVal();
}
}
-RVal GRSimpleVals::EvalComplement(BasicValueFactory& BasicVals, NonLVal X) {
+RVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLVal X) {
switch (X.getSubKind()) {
case nonlval::ConcreteIntKind:
- return cast<nonlval::ConcreteInt>(X).EvalComplement(BasicVals);
+ return cast<nonlval::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
default:
return UnknownVal();
@@ -215,8 +219,11 @@
// Binary operators.
-RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
- NonLVal L, NonLVal R) {
+RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
+ NonLVal L, NonLVal R) {
+
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+
while (1) {
switch (L.getSubKind()) {
@@ -242,7 +249,7 @@
if (isa<nonlval::ConcreteInt>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<nonlval::SymbolVal>(L).getSymbol(), Op,
- cast<nonlval::ConcreteInt>(R).getValue());
+ cast<nonlval::ConcreteInt>(R).getValue());
return nonlval::SymIntConstraintVal(C);
}
@@ -256,7 +263,7 @@
// Binary Operators (except assignments and comma).
-RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
LVal L, LVal R) {
switch (Op) {
@@ -265,23 +272,25 @@
return UnknownVal();
case BinaryOperator::EQ:
- return EvalEQ(BasicVals, L, R);
+ return EvalEQ(Eng, L, R);
case BinaryOperator::NE:
- return EvalNE(BasicVals, L, R);
+ return EvalNE(Eng, L, R);
}
}
// Pointer arithmetic.
-RVal GRSimpleVals::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
LVal L, NonLVal R) {
return UnknownVal();
}
// Equality operators for LVals.
-RVal GRSimpleVals::EvalEQ(BasicValueFactory& BasicVals, LVal L, LVal R) {
+RVal GRSimpleVals::EvalEQ(GRExprEngine& Eng, LVal L, LVal R) {
+
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
switch (L.getSubKind()) {
@@ -337,8 +346,10 @@
return NonLVal::MakeIntTruthVal(BasicVals, false);
}
-RVal GRSimpleVals::EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R) {
+RVal GRSimpleVals::EvalNE(GRExprEngine& Eng, LVal L, LVal R) {
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+
switch (L.getSubKind()) {
default:
@@ -356,8 +367,8 @@
else if (isa<lval::SymbolVal>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
- BinaryOperator::NE,
- cast<lval::ConcreteInt>(L).getValue());
+ BinaryOperator::NE,
+ cast<lval::ConcreteInt>(L).getValue());
return nonlval::SymIntConstraintVal(C);
}
@@ -368,8 +379,8 @@
if (isa<lval::ConcreteInt>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<lval::SymbolVal>(L).getSymbol(),
- BinaryOperator::NE,
- cast<lval::ConcreteInt>(R).getValue());
+ BinaryOperator::NE,
+ cast<lval::ConcreteInt>(R).getValue());
return nonlval::SymIntConstraintVal(C);
}
@@ -398,9 +409,8 @@
//===----------------------------------------------------------------------===//
void GRSimpleVals::EvalCall(ExplodedNodeSet<ValueState>& Dst,
- ValueStateManager& StateMgr,
+ GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
- BasicValueFactory& BasicVals,
CallExpr* CE, LVal L,
ExplodedNode<ValueState>* Pred) {
@@ -411,10 +421,10 @@
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
- RVal V = StateMgr.GetRVal(St, *I);
+ RVal V = Eng.getStateManager().GetRVal(St, *I);
if (isa<LVal>(V))
- St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
+ St = Eng.getStateManager().SetRVal(St, cast<LVal>(V), UnknownVal());
}
Builder.Nodify(Dst, CE, Pred, St);
diff --git a/Analysis/GRSimpleVals.h b/Analysis/GRSimpleVals.h
index 33ccd26..2b3d0fd 100644
--- a/Analysis/GRSimpleVals.h
+++ b/Analysis/GRSimpleVals.h
@@ -28,34 +28,33 @@
// Casts.
- virtual RVal EvalCast(BasicValueFactory& BasicVals, NonLVal V, QualType CastT);
- virtual RVal EvalCast(BasicValueFactory& BasicVals, LVal V, QualType CastT);
+ virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT);
+ virtual RVal EvalCast(GRExprEngine& Engine, LVal V, QualType CastT);
// Unary Operators.
- virtual RVal EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U, NonLVal X);
+ virtual RVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLVal X);
- virtual RVal EvalComplement(BasicValueFactory& BasicVals, NonLVal X);
+ virtual RVal EvalComplement(GRExprEngine& Engine, NonLVal X);
// Binary Operators.
- virtual RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
NonLVal L, NonLVal R);
- virtual RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
LVal L, LVal R);
// Pointer arithmetic.
- virtual RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
LVal L, NonLVal R);
// Calls.
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
- ValueStateManager& StateMgr,
+ GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder,
- BasicValueFactory& BasicVals,
CallExpr* CE, LVal L,
ExplodedNode<ValueState>* Pred);
@@ -63,8 +62,8 @@
// Equality operators for LVals.
- RVal EvalEQ(BasicValueFactory& BasicVals, LVal L, LVal R);
- RVal EvalNE(BasicValueFactory& BasicVals, LVal L, LVal R);
+ RVal EvalEQ(GRExprEngine& Engine, LVal L, LVal R);
+ RVal EvalNE(GRExprEngine& Engine, LVal L, LVal R);
};
} // end clang namespace
diff --git a/Analysis/SymbolManager.cpp b/Analysis/SymbolManager.cpp
index 95fbbb9..5454649 100644
--- a/Analysis/SymbolManager.cpp
+++ b/Analysis/SymbolManager.cpp
@@ -20,30 +20,84 @@
assert (isa<ParmVarDecl>(D) || D->hasGlobalStorage());
- SymbolID& X = DataToSymbol[getKey(D)];
+ llvm::FoldingSetNodeID profile;
- if (!X.isInitialized()) {
- X = SymbolToData.size();
-
- if (ParmVarDecl* VD = dyn_cast<ParmVarDecl>(D))
- SymbolToData.push_back(SymbolDataParmVar(VD));
- else
- SymbolToData.push_back(SymbolDataGlobalVar(D));
+ ParmVarDecl* PD = dyn_cast<ParmVarDecl>(D);
+
+ if (PD)
+ SymbolDataParmVar::Profile(profile, PD);
+ else
+ SymbolDataGlobalVar::Profile(profile, D);
+
+ void* InsertPos;
+
+ SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+
+ if (SD)
+ return SD->getSymbol();
+
+ if (PD) {
+ SD = (SymbolData*) BPAlloc.Allocate<SymbolDataParmVar>();
+ new (SD) SymbolDataParmVar(SymbolCounter, PD);
+ }
+ else {
+ SD = (SymbolData*) BPAlloc.Allocate<SymbolDataGlobalVar>();
+ new (SD) SymbolDataGlobalVar(SymbolCounter, D);
}
- return X;
+ DataSet.InsertNode(SD, InsertPos);
+
+ DataMap[SymbolCounter] = SD;
+ return SymbolCounter++;
}
SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) {
- SymbolID& X = DataToSymbol[getKey(sym)];
- if (!X.isInitialized()) {
- X = SymbolToData.size();
- SymbolToData.push_back(SymbolDataContentsOf(sym));
- }
+ llvm::FoldingSetNodeID profile;
+ SymbolDataContentsOf::Profile(profile, sym);
+ void* InsertPos;
- return X;
+ SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+
+ if (SD)
+ return SD->getSymbol();
+
+ SD = (SymbolData*) BPAlloc.Allocate<SymbolDataContentsOf>();
+ new (SD) SymbolDataContentsOf(SymbolCounter, sym);
+
+
+ DataSet.InsertNode(SD, InsertPos);
+ DataMap[SymbolCounter] = SD;
+
+ return SymbolCounter++;
}
+
+SymbolID SymbolManager::getCallRetValSymbol(CallExpr* CE, unsigned Count) {
+
+ llvm::FoldingSetNodeID profile;
+ SymbolDataCallRetVal::Profile(profile, CE, Count);
+ void* InsertPos;
+
+ SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+
+ if (SD)
+ return SD->getSymbol();
+
+ SD = (SymbolData*) BPAlloc.Allocate<SymbolDataCallRetVal>();
+ new (SD) SymbolDataCallRetVal(SymbolCounter, CE, Count);
+
+ DataSet.InsertNode(SD, InsertPos);
+ DataMap[SymbolCounter] = SD;
+
+ return SymbolCounter++;
+}
+
+const SymbolData& SymbolManager::getSymbolData(SymbolID Sym) const {
+ DataMapTy::const_iterator I = DataMap.find(Sym);
+ assert (I != DataMap.end());
+ return *I->second;
+}
+
QualType SymbolData::getType(const SymbolManager& SymMgr) const {
switch (getKind()) {
@@ -57,12 +111,14 @@
return cast<SymbolDataGlobalVar>(this)->getDecl()->getType();
case ContentsOfKind: {
- SymbolID x = cast<SymbolDataContentsOf>(this)->getSymbol();
+ SymbolID x = cast<SymbolDataContentsOf>(this)->getContainerSymbol();
QualType T = SymMgr.getSymbolData(x).getType(SymMgr);
return T->getAsPointerType()->getPointeeType();
}
+
+ case CallRetValKind:
+ return cast<SymbolDataCallRetVal>(this)->getCallExpr()->getType();
}
}
-SymbolManager::SymbolManager() {}
SymbolManager::~SymbolManager() {}