Index: lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -28,6 +28,8 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include +#include #include using namespace clang; @@ -96,11 +98,6 @@ std::string generateKeyboardNavigationJavascript(); private: - /// \return JavaScript for an option to only show relevant lines. - std::string showRelevantLinesJavascript(const PathDiagnostic &D); - - /// \return Executed lines from \p D in JSON format. - std::string serializeExecutedLines(const PathDiagnostic &D); /// \return Javascript for displaying shortcuts help; std::string showHelpJavascript(); @@ -333,6 +330,115 @@ return os.str(); } +/// Write executed lines from \p D in JSON format into \p os. +static void serializeExecutedLines( + const PathDiagnostic &D, + const PathPieces &path, + llvm::raw_string_ostream &os) { + + // Copy executed lines from path diagnostics. + std::map> ExecutedLines; + for (auto I = D.executedLines_begin(), + E = D.executedLines_end(); I != E; ++I) { + std::set &LinesInFile = ExecutedLines[I->first]; + for (unsigned LineNo : I->second) { + LinesInFile.insert(LineNo); + } + } + + // We need to include all lines for which any kind of diagnostics appears. + for (const auto &P : path) { + FullSourceLoc Loc = P->getLocation().asLocation().getExpansionLoc(); + FileID FID = Loc.getFileID(); + unsigned LineNo = Loc.getLineNumber(); + ExecutedLines[FID.getHashValue()].insert(LineNo); + } + + os << "var relevant_lines = {"; + for (auto I = ExecutedLines.begin(), + E = ExecutedLines.end(); I != E; ++I) { + if (I != ExecutedLines.begin()) + os << ", "; + + os << "\"" << I->first << "\": {"; + for (unsigned LineNo : I->second) { + if (LineNo != *(I->second.begin())) + os << ", "; + + os << "\"" << LineNo << "\": 1"; + } + os << "}"; + } + + os << "};"; +} + +/// \return JavaScript for an option to only show relevant lines. +static std::string showRelevantLinesJavascript( + const PathDiagnostic &D, const PathPieces &path) { + std::string s; + llvm::raw_string_ostream os(s); + os << " + +
+ + +
+)<<<"; + + return os.str(); +} + void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, const SourceManager& SMgr, const PathPieces& path, FileID FID, const FileEntry *Entry, const char *declName) { @@ -357,7 +463,7 @@ // Checkbox and javascript for filtering the output to the counterexample. R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), - showRelevantLinesJavascript(D)); + showRelevantLinesJavascript(D, path)); // Add the name of the file as an

tag. { @@ -507,93 +613,8 @@ )<<<"; } -std::string -HTMLDiagnostics::showRelevantLinesJavascript(const PathDiagnostic &D) { - std::string s; - llvm::raw_string_ostream os(s); - os << " - -
- - -
-)<<<"; - - return os.str(); -} - -std::string HTMLDiagnostics::serializeExecutedLines(const PathDiagnostic &D) { - std::string s; - llvm::raw_string_ostream os(s); - os << "var relevant_lines = {"; - for (auto I = D.executedLines_begin(), - E = D.executedLines_end(); I != E; ++I) { - if (I != D.executedLines_begin()) - os << ", "; - - os << "\"" << I->first << "\": {"; - for (unsigned LineNo : I->second) { - if (LineNo != *(I->second.begin())) - os << ", "; - - os << "\"" << LineNo << "\": 1"; - } - os << "}"; - } - - os << "};"; - return os.str(); -} void HTMLDiagnostics::RewriteFile(Rewriter &R, const SourceManager& SMgr, const PathPieces& path, FileID FID) { @@ -1007,7 +1028,7 @@ navigateTo(/*up=*/true); } else { return; - } + } event.preventDefault(); }, true); Index: test/Analysis/html_diagnostics/relevant_lines/notexecutedlines.c =================================================================== --- test/Analysis/html_diagnostics/relevant_lines/notexecutedlines.c +++ test/Analysis/html_diagnostics/relevant_lines/notexecutedlines.c @@ -0,0 +1,12 @@ +int f() { + int zzz = 200; + zzz += 100; + return 0; +} + +// Show line with the warning even if it wasn't executed (e.g. warning given +// by path-insensitive analysis). +// RUN: rm -rf %t.output +// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,deadcode -analyzer-output html -o %t.output %s +// RUN: cat %t.output/* | FileCheck %s --match-full-lines +// CHECK: var relevant_lines = {"1": {"3": 1}};