[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 llvm-svn: 309968
This commit is contained in:
parent
fd2c379568
commit
f0cadcd9f3
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<SourceManager&>(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<NamedDecl>(DeclWithIssue)) {
|
||||
if (const NamedDecl *ND = dyn_cast<NamedDecl>(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<PathDiagnosticPiece> &p) {
|
||||
return isa<PathDiagnosticNotePiece>(*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<PathDiagnosticNotePiece>(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);
|
||||
}
|
||||
|
||||
llvm::raw_fd_ostream os(FD, true);
|
||||
|
||||
if (filesMade)
|
||||
filesMade->addDiagnostic(D, getName(),
|
||||
llvm::sys::path::filename(ResultPath));
|
||||
|
||||
// Emit the HTML to disk.
|
||||
os << report;
|
||||
}
|
||||
|
||||
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<FileID> 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 << "<hr class=divider>\n";
|
||||
|
||||
os << "<div id=File" << I->getHashValue() << ">\n";
|
||||
|
||||
// Left nav arrow
|
||||
if (I != FileIDs.begin())
|
||||
os << "<div class=FileNav><a href=\"#File" << (I - 1)->getHashValue()
|
||||
<< "\">←</a></div>";
|
||||
|
||||
os << "<h4 class=FileName>" << SMgr.getFileEntryForID(*I)->getName()
|
||||
<< "</h4>\n";
|
||||
|
||||
// Right nav arrow
|
||||
if (I + 1 != E)
|
||||
os << "<div class=FileNav><a href=\"#File" << (I + 1)->getHashValue()
|
||||
<< "\">→</a></div>";
|
||||
|
||||
os << "</div>\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());
|
||||
}
|
||||
}
|
||||
|
||||
// Add line numbers, header, footer, etc.
|
||||
const RewriteBuffer *Buf = R.getRewriteBufferFor(FileIDs[0]);
|
||||
if (!Buf)
|
||||
return "";
|
||||
|
||||
// unsigned FID = R.getSourceMgr().getMainFileID();
|
||||
html::EscapeText(R, FID);
|
||||
html::AddLineNumbers(R, FID);
|
||||
// Add CSS, header, and footer.
|
||||
const FileEntry* Entry = SMgr.getFileEntryForID(FileIDs[0]);
|
||||
FinalizeHTML(D, R, SMgr, path, FileIDs[0], Entry, declName);
|
||||
|
||||
// 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.
|
||||
std::string file;
|
||||
llvm::raw_string_ostream os(file);
|
||||
for (auto BI : *Buf)
|
||||
os << BI;
|
||||
|
||||
html::SyntaxHighlight(R, FID, PP);
|
||||
html::HighlightMacros(R, FID, PP);
|
||||
|
||||
// Get the full directory name of the analyzed file.
|
||||
|
||||
const FileEntry* Entry = SMgr.getFileEntryForID(FID);
|
||||
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);
|
||||
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<PathDiagnosticPiece> &p) {
|
||||
return isa<PathDiagnosticNotePiece>(*p);
|
||||
});
|
||||
|
||||
if (!Buf) {
|
||||
llvm::errs() << "warning: no diagnostics generated for main file.\n";
|
||||
return;
|
||||
unsigned TotalRegularPieces = TotalPieces - TotalNotePieces;
|
||||
unsigned NumRegularPieces = TotalRegularPieces;
|
||||
unsigned NumNotePieces = TotalNotePieces;
|
||||
|
||||
for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) {
|
||||
if (isa<PathDiagnosticNotePiece>(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;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a path for the target HTML file.
|
||||
int FD;
|
||||
SmallString<128> Model, ResultPath;
|
||||
// Add line numbers, header, footer, etc.
|
||||
|
||||
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;
|
||||
}
|
||||
html::EscapeText(R, FID);
|
||||
html::AddLineNumbers(R, FID);
|
||||
|
||||
} 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);
|
||||
}
|
||||
// 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.
|
||||
|
||||
llvm::raw_fd_ostream os(FD, true);
|
||||
|
||||
if (filesMade)
|
||||
filesMade->addDiagnostic(D, getName(),
|
||||
llvm::sys::path::filename(ResultPath));
|
||||
|
||||
// Emit the HTML to disk.
|
||||
for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
|
||||
os << *I;
|
||||
html::SyntaxHighlight(R, FID, PP);
|
||||
html::HighlightMacros(R, FID, PP);
|
||||
}
|
||||
|
||||
void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
|
||||
|
|
|
@ -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.
|
14
clang/test/Analysis/html-diag-singlefile.c
Normal file
14
clang/test/Analysis/html-diag-singlefile.c
Normal file
|
@ -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.
|
10
clang/test/Analysis/html-diags-analyze-headers.c
Normal file
10
clang/test/Analysis/html-diags-analyze-headers.c
Normal file
|
@ -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"
|
5
clang/test/Analysis/html-diags-analyze-headers.h
Normal file
5
clang/test/Analysis/html-diags-analyze-headers.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include "html-diags-multifile.h"
|
||||
|
||||
void test_call_macro() {
|
||||
has_bug(0);
|
||||
}
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: <h3>Annotated Source Code</h3>
|
||||
|
||||
// Make sure it's not generated as a multi-file HTML output
|
||||
// CHECK-NOT: <h4 class=FileName>{{.*}}
|
||||
|
||||
// Without tweaking expr, the expr would hit to the line below
|
||||
// emitted to the output as comment.
|
||||
// CHECK: {{[D]ereference of null pointer}}
|
||||
|
|
21
clang/test/Coverage/html-multifile-diagnostics.c
Normal file
21
clang/test/Coverage/html-multifile-diagnostics.c
Normal file
|
@ -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: <h3>Annotated Source Code</h3>
|
||||
|
||||
// Make sure it's generated as multi-file HTML output
|
||||
// CHECK: <h4 class=FileName>{{.*}}html-multifile-diagnostics.c</h4>
|
||||
// CHECK: <h4 class=FileName>{{.*}}html-multifile-diagnostics.h</h4>
|
||||
|
||||
// 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);
|
||||
}
|
3
clang/test/Coverage/html-multifile-diagnostics.h
Normal file
3
clang/test/Coverage/html-multifile-diagnostics.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
void f1(int *ptr) {
|
||||
*ptr = 0;
|
||||
}
|
|
@ -107,13 +107,6 @@ mailing list</a> to notify other members of the community.</p>
|
|||
|
||||
<li>Bug Reporting
|
||||
<ul>
|
||||
<li>Add support for displaying cross-file diagnostic paths in HTML output
|
||||
(used by <tt>scan-build</tt>).
|
||||
<p>Currently <tt>scan-build</tt> 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. <i>(Difficulty: Medium)</i> </p>
|
||||
</li>
|
||||
|
||||
<li>Refactor path diagnostic generation in <a href="http://clang.llvm.org/doxygen/BugReporter_8cpp_source.html">BugReporter.cpp</a>.
|
||||
<p>It would be great to have more code reuse between "Minimal" and
|
||||
"Extensive" PathDiagnostic generation algorithms. One idea is to create an
|
||||
|
|
Loading…
Reference in a new issue