diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r-- | lib/StaticAnalyzer/Core/AnalysisManager.cpp | 3 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 4 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporter.cpp | 25 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 18 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 2 |
5 files changed, 39 insertions, 13 deletions
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index ebd2336080..09a0debaac 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -24,7 +24,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, : AnaCtxMgr(Options.UnoptimizedCFG, /*AddImplicitDtors=*/true, /*AddInitializers=*/true, - Options.includeTemporaryDtorsInCFG()), + Options.includeTemporaryDtorsInCFG(), + Options.shouldSynthesizeBodies()), Ctx(ctx), Diags(diags), LangOpts(lang), diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index a96dfe1e48..cb7df6b3fd 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -111,3 +111,7 @@ unsigned AnalyzerOptions::getAlwaysInlineSize() const { return AlwaysInlineSize.getValue(); } + +bool AnalyzerOptions::shouldSynthesizeBodies() const { + return getBooleanOption("faux-bodies", false); +} diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 6cbed952c9..e95f31c0d6 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -121,7 +121,8 @@ GetCurrentOrNextStmt(const ExplodedNode *N) { /// Recursively scan through a path and prune out calls and macros pieces /// that aren't needed. Return true if afterwards the path contains /// "interesting stuff" which means it should be pruned from the parent path. -bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R) { +bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R, + PathDiagnosticCallPiece *CallWithLoc) { bool containsSomethingInteresting = false; const unsigned N = pieces.size(); @@ -131,6 +132,11 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R) { IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front()); pieces.pop_front(); + // Throw away pieces with invalid locations. + if (piece->getKind() != PathDiagnosticPiece::Call && + piece->getLocation().asLocation().isInvalid()) + continue; + switch (piece->getKind()) { case PathDiagnosticPiece::Call: { PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece); @@ -142,8 +148,17 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R) { } // Recursively clean out the subclass. Keep this call around if // it contains any informative diagnostics. - if (!RemoveUneededCalls(call->path, R)) + PathDiagnosticCallPiece *NewCallWithLoc = + call->getLocation().asLocation().isValid() + ? call : CallWithLoc; + + if (!RemoveUneededCalls(call->path, R, NewCallWithLoc)) continue; + + if (NewCallWithLoc == CallWithLoc && CallWithLoc) { + call->callEnter = CallWithLoc->callEnter; + } + containsSomethingInteresting = true; break; } @@ -156,6 +171,7 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R) { } case PathDiagnosticPiece::Event: { PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece); + // We never throw away an event, but we do throw it away wholesale // as part of a path if we throw the entire path away. containsSomethingInteresting |= !event->isPrunable(); @@ -954,6 +970,11 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc); const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc); + if (PrevLocClean.asLocation().isInvalid()) { + PrevLoc = NewLoc; + return; + } + if (NewLocClean.asLocation() == PrevLocClean.asLocation()) return; diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 3b4c13471b..3743871361 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -414,7 +414,7 @@ SVal CXXInstanceCall::getCXXThisVal() const { } -RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { +RuntimeDefinition CXXInstanceCall::getRuntimeDefinition(AnalysisDeclContextManager &M) const { // Do we have a decl at all? const Decl *D = getDecl(); if (!D) @@ -423,7 +423,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // If the method is non-virtual, we know we can inline it. const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (!MD->isVirtual()) - return AnyFunctionCall::getRuntimeDefinition(); + return AnyFunctionCall::getRuntimeDefinition(M); // Do we know the implicit 'this' object being called? const MemRegion *R = getCXXThisVal().getAsRegion(); @@ -513,16 +513,16 @@ const Expr *CXXMemberCall::getCXXThisExpr() const { return getOriginExpr()->getImplicitObjectArgument(); } -RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const { +RuntimeDefinition CXXMemberCall::getRuntimeDefinition(AnalysisDeclContextManager &M) const { // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the // id-expression in the class member access expression is a qualified-id, // that function is called. Otherwise, its final overrider in the dynamic type // of the object expression is called. if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee())) if (ME->hasQualifier()) - return AnyFunctionCall::getRuntimeDefinition(); + return AnyFunctionCall::getRuntimeDefinition(M); - return CXXInstanceCall::getRuntimeDefinition(); + return CXXInstanceCall::getRuntimeDefinition(M); } @@ -600,13 +600,13 @@ SVal CXXDestructorCall::getCXXThisVal() const { return UnknownVal(); } -RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { +RuntimeDefinition CXXDestructorCall::getRuntimeDefinition(AnalysisDeclContextManager &M) const { // Base destructors are always called non-virtually. // Skip CXXInstanceCall's devirtualization logic in this case. if (isBaseDestructor()) - return AnyFunctionCall::getRuntimeDefinition(); + return AnyFunctionCall::getRuntimeDefinition(M); - return CXXInstanceCall::getRuntimeDefinition(); + return CXXInstanceCall::getRuntimeDefinition(M); } @@ -790,7 +790,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, llvm_unreachable("The while loop should always terminate."); } -RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { +RuntimeDefinition ObjCMethodCall::getRuntimeDefinition(AnalysisDeclContextManager &M) const { const ObjCMessageExpr *E = getOriginExpr(); assert(E); Selector Sel = E->getSelector(); diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index eb5395e93c..9d4d16c6cd 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -640,7 +640,7 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, // If we already tried once and failed, make sure we don't retry later. State = InlinedFailedState; } else { - RuntimeDefinition RD = Call->getRuntimeDefinition(); + RuntimeDefinition RD = Call->getRuntimeDefinition(AnalysisDeclContexts); const Decl *D = RD.getDecl(); if (D) { if (RD.mayHaveOtherDefinitions()) { |