/// usually because it could not reason about something.
BlocksAborted blocksAborted;
- /// The functions which have been analyzed through inlining. This is owned by
- /// AnalysisConsumer. It can be null.
- SetOfConstDecls *AnalyzedCallees;
-
/// The information about functions shared by the whole translation unit.
/// (This data is owned by AnalysisConsumer.)
FunctionSummariesTy *FunctionSummaries;
public:
/// Construct a CoreEngine object to analyze the provided CFG.
- CoreEngine(SubEngine& subengine, SetOfConstDecls *VisitedCallees,
+ CoreEngine(SubEngine& subengine,
FunctionSummariesTy *FS)
: SubEng(subengine), G(new ExplodedGraph()),
WList(WorkList::makeDFS()),
BCounterFactory(G->getAllocator()),
- AnalyzedCallees(VisitedCallees),
FunctionSummaries(FS){}
/// getGraph - Returns the exploded graph.
/// destructor is called before the rest of the ExprEngine is destroyed.
GRBugReporter BR;
+ /// The functions which have been analyzed through inlining. This is owned by
+ /// AnalysisConsumer. It can be null.
+ SetOfConstDecls *VisitedCallees;
+
public:
ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCallees,
+ SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS);
~ExprEngine();
case ProgramPoint::CallEnterKind: {
CallEnter CEnter = cast<CallEnter>(Loc);
- if (AnalyzedCallees)
- if (const CallExpr* CE =
- dyn_cast_or_null<CallExpr>(CEnter.getCallExpr()))
- if (const Decl *CD = CE->getCalleeDecl())
- AnalyzedCallees->insert(CD);
SubEng.processCallEnter(CEnter, Pred);
break;
}
//===----------------------------------------------------------------------===//
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCallees,
+ SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS)
: AMgr(mgr),
AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
- Engine(*this, VisitedCallees, FS),
+ Engine(*this, FS),
G(Engine.getGraph()),
StateMgr(getContext(), mgr.getStoreManagerCreator(),
mgr.getConstraintManagerCreator(), G.getAllocator(),
currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", getContext())),
- ObjCGCEnabled(gcEnabled), BR(mgr, *this)
+ ObjCGCEnabled(gcEnabled), BR(mgr, *this),
+ VisitedCallees(VisitedCalleesIn)
{
if (mgr.options.eagerlyTrimExplodedGraph) {
// Enable eager node reclaimation when constructing the ExplodedGraph.
NumInlinedCalls++;
+ // Mark the decl as visited.
+ if (VisitedCallees)
+ VisitedCallees->insert(D);
+
return true;
}
}
}
+static bool shouldSkipFunction(CallGraphNode *N,
+ SmallPtrSet<CallGraphNode*,24> Visited) {
+ // We want to re-analyse the functions as top level in several cases:
+ // - The 'init' methods should be reanalyzed because
+ // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns
+ // 'nil' and unless we analyze the 'init' functions as top level, we will not
+ // catch errors within defensive code.
+ // - We want to reanalyze all ObjC methods as top level to report Retain
+ // Count naming convention errors more aggressively.
+ if (isa<ObjCMethodDecl>(N->getDecl()))
+ return false;
+
+ // Otherwise, if we visited the function before, do not reanalyze it.
+ return Visited.count(N);
+}
+
void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) {
// Otherwise, use the Callgraph to derive the order.
// Build the Call Graph.
// Push the children into the queue.
for (CallGraphNode::const_iterator CI = N->begin(),
CE = N->end(); CI != CE; ++CI) {
- if (!Visited.count(*CI))
+ if (!shouldSkipFunction(*CI, Visited))
BFSQueue.push_back(*CI);
}
// Skip the functions which have been processed already or previously
// inlined.
- if (Visited.count(N))
+ if (shouldSkipFunction(N, Visited))
continue;
// Analyze the function.