From 896feaf77bafc5473b5f7d990c7e99ac2ca33d8c Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Thu, 3 Aug 2017 18:12:22 +0000 Subject: [PATCH] [Analyzer] Add support for displaying cross-file diagnostic paths in HTML output This change adds support for cross-file diagnostic paths in html output. If the diagnostic path is not cross-file, there is no change in the output. Patch by Vlad Tsyrklevich! Differential Revision: https://reviews.llvm.org/D30406 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@309968 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../clang/StaticAnalyzer/Core/Analyses.def | 5 +- lib/Rewrite/HTMLRewrite.cpp | 5 + lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp | 314 ++++++++++++------ .../diagnostics/diag-cross-file-boundaries.c | 12 - test/Analysis/html-diag-singlefile.c | 14 + ...le-boundaries.h => html-diag-singlefile.h} | 0 test/Analysis/html-diags-analyze-headers.c | 10 + test/Analysis/html-diags-analyze-headers.h | 5 + test/Analysis/html-diags-multifile.c | 5 +- test/Analysis/html-diags.c | 6 + test/Coverage/html-diagnostics.c | 7 + test/Coverage/html-multifile-diagnostics.c | 21 ++ test/Coverage/html-multifile-diagnostics.h | 3 + www/analyzer/open_projects.html | 7 - 14 files changed, 285 insertions(+), 129 deletions(-) delete mode 100644 test/Analysis/diagnostics/diag-cross-file-boundaries.c create mode 100644 test/Analysis/html-diag-singlefile.c rename test/Analysis/{diagnostics/diag-cross-file-boundaries.h => html-diag-singlefile.h} (100%) create mode 100644 test/Analysis/html-diags-analyze-headers.c create mode 100644 test/Analysis/html-diags-analyze-headers.h create mode 100644 test/Coverage/html-multifile-diagnostics.c create mode 100644 test/Coverage/html-multifile-diagnostics.h diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def index 04bf41bfde..281a2ac3a6 100644 --- a/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/include/clang/StaticAnalyzer/Core/Analyses.def @@ -28,9 +28,10 @@ ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3Con #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis results using HTML (not allowing for multi-file bugs)", createHTMLSingleFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index 9e307f31be..23d1895e31 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -289,6 +289,11 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter &R, FileID FID, " body { color:#000000; background-color:#ffffff }\n" " body { font-family:Helvetica, sans-serif; font-size:10pt }\n" " h1 { font-size:14pt }\n" + " .FileName { margin-top: 5px; margin-bottom: 5px; display: inline; }\n" + " .FileNav { margin-left: 5px; margin-right: 5px; display: inline; }\n" + " .FileNav a { text-decoration:none; font-size: larger; }\n" + " .divider { margin-top: 30px; margin-bottom: 30px; height: 15px; }\n" + " .divider { background-color: gray; }\n" " .code { border-collapse:collapse; width:100%; }\n" " .code { font-family: \"Monospace\", monospace; font-size:10pt }\n" " .code { line-height: 1.2em }\n" diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index f0f6dd2e43..9b820e81e3 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -44,8 +44,12 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { bool createdDir, noDir; const Preprocessor &PP; AnalyzerOptions &AnalyzerOpts; + const bool SupportsCrossFileDiagnostics; public: - HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string& prefix, + const Preprocessor &pp, + bool supportsMultipleFiles); ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } @@ -56,6 +60,10 @@ public: return "HTMLDiagnostics"; } + bool supportsCrossFileDiagnostics() const override { + return SupportsCrossFileDiagnostics; + } + unsigned ProcessMacroPiece(raw_ostream &os, const PathDiagnosticMacroPiece& P, unsigned num); @@ -69,21 +77,47 @@ public: void ReportDiag(const PathDiagnostic& D, FilesMade *filesMade); + + // Generate the full HTML report + std::string GenerateHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, + const char *declName); + + // Add HTML header/footers to file specified by FID + void FinalizeHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, + FileID FID, const FileEntry *Entry, const char *declName); + + // Rewrite the file specified by FID with HTML formatting. + void RewriteFile(Rewriter &R, const SourceManager& SMgr, + const PathPieces& path, FileID FID); }; } // end anonymous namespace HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, - const Preprocessor &pp) - : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) { -} + const Preprocessor &pp, + bool supportsMultipleFiles) + : Directory(prefix), + createdDir(false), + noDir(false), + PP(pp), + AnalyzerOpts(AnalyzerOpts), + SupportsCrossFileDiagnostics(supportsMultipleFiles) {} void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string& prefix, const Preprocessor &PP) { - C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP)); + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, true)); +} + +void ento::createHTMLSingleFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, + PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP) { + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, false)); } //===----------------------------------------------------------------------===// @@ -121,24 +155,24 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // First flatten out the entire path to make it easier to use. PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false); - // The path as already been prechecked that all parts of the path are - // from the same file and that it is non-empty. - const SourceManager &SMgr = path.front()->getLocation().getManager(); + // The path as already been prechecked that the path is non-empty. assert(!path.empty()); - FileID FID = - path.front()->getLocation().asLocation().getExpansionLoc().getFileID(); - assert(FID.isValid()); + const SourceManager &SMgr = path.front()->getLocation().getManager(); // Create a new rewriter to generate HTML. Rewriter R(const_cast(SMgr), PP.getLangOpts()); + // The file for the first path element is considered the main report file, it + // will usually be equivalent to SMgr.getMainFileID(); however, it might be a + // header when -analyzer-opt-analyze-headers is used. + FileID ReportFile = path.front()->getLocation().asLocation().getExpansionLoc().getFileID(); + // Get the function/method name SmallString<128> declName("unknown"); int offsetDecl = 0; if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { - if (const NamedDecl *ND = dyn_cast(DeclWithIssue)) { + if (const NamedDecl *ND = dyn_cast(DeclWithIssue)) declName = ND->getDeclName().getAsString(); - } if (const Stmt *Body = DeclWithIssue->getBody()) { // Retrieve the relative position of the declaration which will be used @@ -151,49 +185,144 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, } } - // Process the path. - // Maintain the counts of extra note pieces separately. - unsigned TotalPieces = path.size(); - unsigned TotalNotePieces = - std::count_if(path.begin(), path.end(), - [](const std::shared_ptr &p) { - return isa(*p); - }); + std::string report = GenerateHTML(D, R, SMgr, path, declName.c_str()); + if (report.empty()) { + llvm::errs() << "warning: no diagnostics generated for main file.\n"; + return; + } - unsigned TotalRegularPieces = TotalPieces - TotalNotePieces; - unsigned NumRegularPieces = TotalRegularPieces; - unsigned NumNotePieces = TotalNotePieces; + // Create a path for the target HTML file. + int FD; + SmallString<128> Model, ResultPath; - for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) { - if (isa(I->get())) { - // This adds diagnostic bubbles, but not navigation. - // Navigation through note pieces would be added later, - // as a separate pass through the piece list. - HandlePiece(R, FID, **I, NumNotePieces, TotalNotePieces); - --NumNotePieces; - } else { - HandlePiece(R, FID, **I, NumRegularPieces, TotalRegularPieces); - --NumRegularPieces; - } + if (!AnalyzerOpts.shouldWriteStableReportFilename()) { + llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); + if (std::error_code EC = + llvm::sys::fs::make_absolute(Model)) { + llvm::errs() << "warning: could not make '" << Model + << "' absolute: " << EC.message() << '\n'; + return; + } + if (std::error_code EC = + llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) { + llvm::errs() << "warning: could not create file in '" << Directory + << "': " << EC.message() << '\n'; + return; + } + + } else { + int i = 1; + std::error_code EC; + do { + // Find a filename which is not already used + const FileEntry* Entry = SMgr.getFileEntryForID(ReportFile); + std::stringstream filename; + Model = ""; + filename << "report-" + << llvm::sys::path::filename(Entry->getName()).str() + << "-" << declName.c_str() + << "-" << offsetDecl + << "-" << i << ".html"; + llvm::sys::path::append(Model, Directory, + filename.str()); + EC = llvm::sys::fs::openFileForWrite(Model, + FD, + llvm::sys::fs::F_RW | + llvm::sys::fs::F_Excl); + if (EC && EC != llvm::errc::file_exists) { + llvm::errs() << "warning: could not create file '" << Model + << "': " << EC.message() << '\n'; + return; + } + i++; + } while (EC); } - // Add line numbers, header, footer, etc. + llvm::raw_fd_ostream os(FD, true); - // unsigned FID = R.getSourceMgr().getMainFileID(); - html::EscapeText(R, FID); - html::AddLineNumbers(R, FID); + if (filesMade) + filesMade->addDiagnostic(D, getName(), + llvm::sys::path::filename(ResultPath)); - // If we have a preprocessor, relex the file and syntax highlight. - // We might not have a preprocessor if we come from a deserialized AST file, - // for example. + // Emit the HTML to disk. + os << report; +} - html::SyntaxHighlight(R, FID, PP); - html::HighlightMacros(R, FID, PP); +std::string HTMLDiagnostics::GenerateHTML(const PathDiagnostic& D, Rewriter &R, + const SourceManager& SMgr, const PathPieces& path, const char *declName) { + + // Rewrite source files as HTML for every new file the path crosses + std::vector FileIDs; + for (auto I : path) { + FileID FID = I->getLocation().asLocation().getExpansionLoc().getFileID(); + if (std::find(FileIDs.begin(), FileIDs.end(), FID) != FileIDs.end()) + continue; + + FileIDs.push_back(FID); + RewriteFile(R, SMgr, path, FID); + } + + if (SupportsCrossFileDiagnostics && FileIDs.size() > 1) { + // Prefix file names, anchor tags, and nav cursors to every file + for (auto I = FileIDs.begin(), E = FileIDs.end(); I != E; I++) { + std::string s; + llvm::raw_string_ostream os(s); + + if (I != FileIDs.begin()) + os << "
\n"; + + os << "
getHashValue() << ">\n"; - // Get the full directory name of the analyzed file. + // Left nav arrow + if (I != FileIDs.begin()) + os << ""; - const FileEntry* Entry = SMgr.getFileEntryForID(FID); + os << "

" << SMgr.getFileEntryForID(*I)->getName() + << "

\n"; + // Right nav arrow + if (I + 1 != E) + os << ""; + + os << "
\n"; + + R.InsertTextBefore(SMgr.getLocForStartOfFile(*I), os.str()); + } + + // Append files to the main report file in the order they appear in the path + for (auto I : llvm::make_range(FileIDs.begin() + 1, FileIDs.end())) { + std::string s; + llvm::raw_string_ostream os(s); + + const RewriteBuffer *Buf = R.getRewriteBufferFor(I); + for (auto BI : *Buf) + os << BI; + + R.InsertTextAfter(SMgr.getLocForEndOfFile(FileIDs[0]), os.str()); + } + } + + const RewriteBuffer *Buf = R.getRewriteBufferFor(FileIDs[0]); + if (!Buf) + return ""; + + // Add CSS, header, and footer. + const FileEntry* Entry = SMgr.getFileEntryForID(FileIDs[0]); + FinalizeHTML(D, R, SMgr, path, FileIDs[0], Entry, declName); + + std::string file; + llvm::raw_string_ostream os(file); + for (auto BI : *Buf) + os << BI; + + 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) { // This is a cludge; basically we want to append either the full // working directory if we have no directory information. This is // a work in progress. @@ -306,73 +435,48 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); } - // Add CSS, header, and footer. - html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName()); +} - // Get the rewrite buffer. - const RewriteBuffer *Buf = R.getRewriteBufferFor(FID); - - if (!Buf) { - llvm::errs() << "warning: no diagnostics generated for main file.\n"; - return; - } - - // Create a path for the target HTML file. - int FD; - SmallString<128> Model, ResultPath; +void HTMLDiagnostics::RewriteFile(Rewriter &R, const SourceManager& SMgr, + const PathPieces& path, FileID FID) { + // Process the path. + // Maintain the counts of extra note pieces separately. + unsigned TotalPieces = path.size(); + unsigned TotalNotePieces = + std::count_if(path.begin(), path.end(), + [](const std::shared_ptr &p) { + return isa(*p); + }); - if (!AnalyzerOpts.shouldWriteStableReportFilename()) { - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (std::error_code EC = - llvm::sys::fs::make_absolute(Model)) { - llvm::errs() << "warning: could not make '" << Model - << "' absolute: " << EC.message() << '\n'; - return; - } - if (std::error_code EC = - llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) { - llvm::errs() << "warning: could not create file in '" << Directory - << "': " << EC.message() << '\n'; - return; - } + unsigned TotalRegularPieces = TotalPieces - TotalNotePieces; + unsigned NumRegularPieces = TotalRegularPieces; + unsigned NumNotePieces = TotalNotePieces; - } else { - int i = 1; - std::error_code EC; - do { - // Find a filename which is not already used - std::stringstream filename; - Model = ""; - filename << "report-" - << llvm::sys::path::filename(Entry->getName()).str() - << "-" << declName.c_str() - << "-" << offsetDecl - << "-" << i << ".html"; - llvm::sys::path::append(Model, Directory, - filename.str()); - EC = llvm::sys::fs::openFileForWrite(Model, - FD, - llvm::sys::fs::F_RW | - llvm::sys::fs::F_Excl); - if (EC && EC != llvm::errc::file_exists) { - llvm::errs() << "warning: could not create file '" << Model - << "': " << EC.message() << '\n'; - return; - } - i++; - } while (EC); + for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) { + if (isa(I->get())) { + // This adds diagnostic bubbles, but not navigation. + // Navigation through note pieces would be added later, + // as a separate pass through the piece list. + HandlePiece(R, FID, **I, NumNotePieces, TotalNotePieces); + --NumNotePieces; + } else { + HandlePiece(R, FID, **I, NumRegularPieces, TotalRegularPieces); + --NumRegularPieces; + } } - llvm::raw_fd_ostream os(FD, true); + // Add line numbers, header, footer, etc. - if (filesMade) - filesMade->addDiagnostic(D, getName(), - llvm::sys::path::filename(ResultPath)); + html::EscapeText(R, FID); + html::AddLineNumbers(R, FID); - // Emit the HTML to disk. - for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I) - os << *I; + // If we have a preprocessor, relex the file and syntax highlight. + // We might not have a preprocessor if we come from a deserialized AST file, + // for example. + + html::SyntaxHighlight(R, FID, PP); + html::HighlightMacros(R, FID, PP); } void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.c b/test/Analysis/diagnostics/diag-cross-file-boundaries.c deleted file mode 100644 index b975af3fb2..0000000000 --- a/test/Analysis/diagnostics/diag-cross-file-boundaries.c +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html -o PR12421.html %s 2>&1 | FileCheck %s - -// Test for PR12421 -#include "diag-cross-file-boundaries.h" - -int main(){ - f(); - return 0; -} - -// CHECK: warning: Path diagnostic report is not generated. diff --git a/test/Analysis/html-diag-singlefile.c b/test/Analysis/html-diag-singlefile.c new file mode 100644 index 0000000000..fc0dcc7a42 --- /dev/null +++ b/test/Analysis/html-diag-singlefile.c @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html-single-file -o D30406.html %s 2>&1 | FileCheck %s + +// Check that single file HTML output does not process multi-file diagnostics. +// (This used to test for PR12421, before the introduction of the html-single-file format) + +#include "html-diag-singlefile.h" + +int main(){ + f(); + return 0; +} + +// CHECK: warning: Path diagnostic report is not generated. diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.h b/test/Analysis/html-diag-singlefile.h similarity index 100% rename from test/Analysis/diagnostics/diag-cross-file-boundaries.h rename to test/Analysis/html-diag-singlefile.h diff --git a/test/Analysis/html-diags-analyze-headers.c b/test/Analysis/html-diags-analyze-headers.c new file mode 100644 index 0000000000..fa5f21de04 --- /dev/null +++ b/test/Analysis/html-diags-analyze-headers.c @@ -0,0 +1,10 @@ +// RUN: mkdir -p %t.dir +// RUN: %clang_analyze_cc1 -analyzer-opt-analyze-headers -analyzer-output=html -analyzer-checker=core -o %t.dir %s +// RUN: ls %t.dir | grep report +// RUN: rm -rf %t.dir + +// This tests that we emit HTML diagnostics for reports in headers when the +// analyzer is run with -analyzer-opt-analyze-headers. This was handled +// incorrectly in the first iteration of D30406. + +#include "html-diags-analyze-headers.h" diff --git a/test/Analysis/html-diags-analyze-headers.h b/test/Analysis/html-diags-analyze-headers.h new file mode 100644 index 0000000000..3641ca9c04 --- /dev/null +++ b/test/Analysis/html-diags-analyze-headers.h @@ -0,0 +1,5 @@ +#include "html-diags-multifile.h" + +void test_call_macro() { + has_bug(0); +} diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c index ce1f72b6bb..ff7b625ad0 100644 --- a/test/Analysis/html-diags-multifile.c +++ b/test/Analysis/html-diags-multifile.c @@ -1,10 +1,9 @@ // RUN: mkdir -p %t.dir // RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %t.dir %s -// RUN: ls %t.dir | not grep report +// RUN: ls %t.dir | grep report // RUN: rm -fR %t.dir -// This tests that we do not currently emit HTML diagnostics for reports that -// cross file boundaries. +// This tests that we emit HTML diagnostics for reports that cross file boundaries. #include "html-diags-multifile.h" diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c index 182bcfbdfa..dd185b542a 100644 --- a/test/Analysis/html-diags.c +++ b/test/Analysis/html-diags.c @@ -3,6 +3,12 @@ // RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %T/dir %s // RUN: ls %T/dir | grep report +// D30406: Test new html-single-file output +// RUN: rm -fR %T/dir +// RUN: mkdir %T/dir +// RUN: %clang_analyze_cc1 -analyzer-output=html-single-file -analyzer-checker=core -o %T/dir %s +// RUN: ls %T/dir | grep report + // PR16547: Test relative paths // RUN: cd %T/dir // RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o testrelative %s diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c index 045943ae8b..34b86cd982 100644 --- a/test/Coverage/html-diagnostics.c +++ b/test/Coverage/html-diagnostics.c @@ -1,11 +1,18 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s // RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s +// +// RUN: rm -rf %t +// RUN: %clang_cc1 -analyze -analyzer-output=html-single-file -analyzer-checker=core -o %t %s +// RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s // REQUIRES: staticanalyzer // CHECK:

Annotated Source Code

+// Make sure it's not generated as a multi-file HTML output +// CHECK-NOT:

{{.*}} + // Without tweaking expr, the expr would hit to the line below // emitted to the output as comment. // CHECK: {{[D]ereference of null pointer}} diff --git a/test/Coverage/html-multifile-diagnostics.c b/test/Coverage/html-multifile-diagnostics.c new file mode 100644 index 0000000000..abd54ae839 --- /dev/null +++ b/test/Coverage/html-multifile-diagnostics.c @@ -0,0 +1,21 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s +// RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s + +// REQUIRES: staticanalyzer + +// CHECK:

Annotated Source Code

+ +// Make sure it's generated as multi-file HTML output +// CHECK:

{{.*}}html-multifile-diagnostics.c

+// CHECK:

{{.*}}html-multifile-diagnostics.h

+ +// Without tweaking expr, the expr would hit to the line below +// emitted to the output as comment. +// CHECK: {{[D]ereference of null pointer}} + +#include "html-multifile-diagnostics.h" + +void f0() { + f1((int*)0); +} diff --git a/test/Coverage/html-multifile-diagnostics.h b/test/Coverage/html-multifile-diagnostics.h new file mode 100644 index 0000000000..4a99ff0df9 --- /dev/null +++ b/test/Coverage/html-multifile-diagnostics.h @@ -0,0 +1,3 @@ +void f1(int *ptr) { + *ptr = 0; +} diff --git a/www/analyzer/open_projects.html b/www/analyzer/open_projects.html index f354015c3f..744f4eca41 100644 --- a/www/analyzer/open_projects.html +++ b/www/analyzer/open_projects.html @@ -107,13 +107,6 @@ mailing list to notify other members of the community.

  • Bug Reporting
      -
    • Add support for displaying cross-file diagnostic paths in HTML output - (used by scan-build). -

      Currently scan-build output does not display reports that span - multiple files. The main problem is that we do not have a good format to - display such paths in HTML output. (Difficulty: Medium)

      -
    • -
    • Refactor path diagnostic generation in BugReporter.cpp.

      It would be great to have more code reuse between "Minimal" and "Extensive" PathDiagnostic generation algorithms. One idea is to create an -- 2.40.0