aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp25
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp2
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()) {