aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/BugReporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporter.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp107
1 files changed, 86 insertions, 21 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 488126b0088a..53b4e699f7ad 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -78,7 +79,9 @@ static PathDiagnosticEventPiece *
eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
PathDiagnosticEventPiece *Y) {
// Prefer diagnostics that come from ConditionBRVisitor over
- // those that came from TrackConstraintBRVisitor.
+ // those that came from TrackConstraintBRVisitor,
+ // unless the one from ConditionBRVisitor is
+ // its generic fallback diagnostic.
const void *tagPreferred = ConditionBRVisitor::getTag();
const void *tagLesser = TrackConstraintBRVisitor::getTag();
@@ -86,10 +89,10 @@ eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
return nullptr;
if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
- return X;
+ return ConditionBRVisitor::isPieceMessageGeneric(X) ? Y : X;
if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
- return Y;
+ return ConditionBRVisitor::isPieceMessageGeneric(Y) ? X : Y;
return nullptr;
}
@@ -112,15 +115,15 @@ static void removeRedundantMsgs(PathPieces &path) {
path.pop_front();
switch (piece->getKind()) {
- case clang::ento::PathDiagnosticPiece::Call:
+ case PathDiagnosticPiece::Call:
removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path);
break;
- case clang::ento::PathDiagnosticPiece::Macro:
+ case PathDiagnosticPiece::Macro:
removeRedundantMsgs(cast<PathDiagnosticMacroPiece>(piece)->subPieces);
break;
- case clang::ento::PathDiagnosticPiece::ControlFlow:
+ case PathDiagnosticPiece::ControlFlow:
break;
- case clang::ento::PathDiagnosticPiece::Event: {
+ case PathDiagnosticPiece::Event: {
if (i == N-1)
break;
@@ -140,6 +143,8 @@ static void removeRedundantMsgs(PathPieces &path) {
}
break;
}
+ case PathDiagnosticPiece::Note:
+ break;
}
path.push_back(piece);
}
@@ -197,6 +202,9 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
}
case PathDiagnosticPiece::ControlFlow:
break;
+
+ case PathDiagnosticPiece::Note:
+ break;
}
pieces.push_back(piece);
@@ -3104,6 +3112,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
+ R->addVisitor(llvm::make_unique<CXXSelfAssignmentBRVisitor>());
BugReport::VisitorList visitors;
unsigned origReportConfigToken, finalReportConfigToken;
@@ -3277,6 +3286,19 @@ struct FRIEC_WLItem {
};
}
+static const CFGBlock *findBlockForNode(const ExplodedNode *N) {
+ ProgramPoint P = N->getLocation();
+ if (auto BEP = P.getAs<BlockEntrance>())
+ return BEP->getBlock();
+
+ // Find the node's current statement in the CFG.
+ if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
+ return N->getLocationContext()->getAnalysisDeclContext()
+ ->getCFGStmtMap()->getBlock(S);
+
+ return nullptr;
+}
+
static BugReport *
FindReportInEquivalenceClass(BugReportEquivClass& EQ,
SmallVectorImpl<BugReport*> &bugReports) {
@@ -3325,6 +3347,18 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
continue;
}
+ // See if we are in a no-return CFG block. If so, treat this similarly
+ // to being post-dominated by a sink. This works better when the analysis
+ // is incomplete and we have never reached a no-return function
+ // we're post-dominated by.
+ // This is not quite enough to handle the incomplete analysis case.
+ // We may be post-dominated in subsequent blocks, or even
+ // inter-procedurally. However, it is not clear if more complicated
+ // cases are generally worth suppressing.
+ if (const CFGBlock *B = findBlockForNode(errorNode))
+ if (B->hasNoReturnElement())
+ continue;
+
// At this point we know that 'N' is not a sink and it has at least one
// successor. Use a DFS worklist to find a non-sink end-of-path node.
typedef FRIEC_WLItem WLItem;
@@ -3402,25 +3436,28 @@ void BugReporter::FlushReport(BugReport *exampleReport,
exampleReport->getUniqueingLocation(),
exampleReport->getUniqueingDecl()));
- MaxBugClassSize = std::max(bugReports.size(),
- static_cast<size_t>(MaxBugClassSize));
+ if (exampleReport->isPathSensitive()) {
+ // Generate the full path diagnostic, using the generation scheme
+ // specified by the PathDiagnosticConsumer. Note that we have to generate
+ // path diagnostics even for consumers which do not support paths, because
+ // the BugReporterVisitors may mark this bug as a false positive.
+ assert(!bugReports.empty());
+
+ MaxBugClassSize =
+ std::max(bugReports.size(), static_cast<size_t>(MaxBugClassSize));
- // Generate the full path diagnostic, using the generation scheme
- // specified by the PathDiagnosticConsumer. Note that we have to generate
- // path diagnostics even for consumers which do not support paths, because
- // the BugReporterVisitors may mark this bug as a false positive.
- if (!bugReports.empty())
if (!generatePathDiagnostic(*D.get(), PD, bugReports))
return;
- MaxValidBugClassSize = std::max(bugReports.size(),
- static_cast<size_t>(MaxValidBugClassSize));
+ MaxValidBugClassSize =
+ std::max(bugReports.size(), static_cast<size_t>(MaxValidBugClassSize));
- // Examine the report and see if the last piece is in a header. Reset the
- // report location to the last piece in the main source file.
- AnalyzerOptions& Opts = getAnalyzerOptions();
- if (Opts.shouldReportIssuesInMainSourceFile() && !Opts.AnalyzeAll)
- D->resetDiagnosticLocationToMainFile();
+ // Examine the report and see if the last piece is in a header. Reset the
+ // report location to the last piece in the main source file.
+ AnalyzerOptions &Opts = getAnalyzerOptions();
+ if (Opts.shouldReportIssuesInMainSourceFile() && !Opts.AnalyzeAll)
+ D->resetDiagnosticLocationToMainFile();
+ }
// If the path is empty, generate a single step path with the location
// of the issue.
@@ -3433,6 +3470,27 @@ void BugReporter::FlushReport(BugReport *exampleReport,
D->setEndOfPath(std::move(piece));
}
+ PathPieces &Pieces = D->getMutablePieces();
+ if (getAnalyzerOptions().shouldDisplayNotesAsEvents()) {
+ // For path diagnostic consumers that don't support extra notes,
+ // we may optionally convert those to path notes.
+ for (auto I = exampleReport->getNotes().rbegin(),
+ E = exampleReport->getNotes().rend(); I != E; ++I) {
+ PathDiagnosticNotePiece *Piece = I->get();
+ PathDiagnosticEventPiece *ConvertedPiece =
+ new PathDiagnosticEventPiece(Piece->getLocation(),
+ Piece->getString());
+ for (const auto &R: Piece->getRanges())
+ ConvertedPiece->addRange(R);
+
+ Pieces.push_front(ConvertedPiece);
+ }
+ } else {
+ for (auto I = exampleReport->getNotes().rbegin(),
+ E = exampleReport->getNotes().rend(); I != E; ++I)
+ Pieces.push_front(*I);
+ }
+
// Get the meta data.
const BugReport::ExtraTextList &Meta = exampleReport->getExtraText();
for (BugReport::ExtraTextList::const_iterator i = Meta.begin(),
@@ -3517,6 +3575,13 @@ LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const {
// FIXME: Print which macro is being invoked.
}
+LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const {
+ llvm::errs() << "NOTE\n--------------\n";
+ llvm::errs() << getString() << "\n";
+ llvm::errs() << " ---- at ----\n";
+ getLocation().dump();
+}
+
LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const {
if (!isValid()) {
llvm::errs() << "<INVALID>\n";