Static Analyzer: When generating plists for errors reports, generate one plist file per translation unit that contains all of the diagnostics.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62647 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2009-01-21 00:42:24 +00:00
Родитель 10a4231e73
Коммит ddf32dabe7
3 изменённых файлов: 90 добавлений и 68 удалений

Просмотреть файл

@ -211,9 +211,9 @@ void NamedDecl::ReadInRec(Deserializer& D, ASTContext& C) {
= static_cast<DeclarationName::NameKind>(D.ReadInt());
switch (Kind) {
case DeclarationName::Identifier: {
IdentifierInfo *Identifier;
D.ReadPtr(Identifier);
Name = Identifier;
// Don't allow back-patching. The IdentifierInfo table must already
// be loaded.
Name = D.ReadPtr<IdentifierInfo>();
break;
}

Просмотреть файл

@ -31,19 +31,17 @@ namespace clang {
namespace {
class VISIBILITY_HIDDEN PlistDiagnostics : public PathDiagnosticClient {
llvm::sys::Path Directory, FilePrefix;
bool createdDir, noDir;
std::vector<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
public:
PlistDiagnostics(const std::string& prefix);
~PlistDiagnostics() {}
~PlistDiagnostics();
void HandlePathDiagnostic(const PathDiagnostic* D);
};
} // end anonymous namespace
PlistDiagnostics::PlistDiagnostics(const std::string& prefix)
: Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false) {
FilePrefix.appendComponent("report"); // All Plist files begin with "report"
}
PlistDiagnostics::PlistDiagnostics(const std::string& output)
: OutputFile(output) {}
PathDiagnosticClient*
clang::CreatePlistDiagnosticClient(const std::string& s,
@ -139,72 +137,54 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
}
void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
// Create an owning smart pointer for 'D' just so that we auto-free it
// when we exit this method.
llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D));
if (!D)
return;
// Create the directory to contain the plist files if it is missing.
if (!createdDir) {
createdDir = true;
std::string ErrorMsg;
Directory.createDirectoryOnDisk(true, &ErrorMsg);
if (!Directory.isDirectory()) {
llvm::errs() << "warning: could not create directory '"
<< Directory.toString() << "'\n"
<< "reason: " << ErrorMsg << '\n';
noDir = true;
return;
}
if (D->empty()) {
delete D;
return;
}
if (noDir)
return;
BatchedDiags.push_back(D);
}
// Get the source manager.
SourceManager& SM = D->begin()->getLocation().getManager();
PlistDiagnostics::~PlistDiagnostics() {
// Build up a set of FIDs that we use by scanning the locations and
// ranges of the diagnostics.
FIDMap FM;
llvm::SmallVector<FileID, 10> Fids;
for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) {
AddFID(FM, Fids, SM, I->getLocation());
SourceManager& SM = (*BatchedDiags.begin())->begin()->getLocation().getManager();
for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
RE=I->ranges_end(); RI!=RE; ++RI) {
AddFID(FM, Fids, SM, RI->getBegin());
AddFID(FM, Fids, SM, RI->getEnd());
for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(),
DE = BatchedDiags.end(); DI != DE; ++DI) {
const PathDiagnostic *D = *DI;
for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I!=E; ++I) {
AddFID(FM, Fids, SM, I->getLocation());
for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
RE=I->ranges_end(); RI!=RE; ++RI) {
AddFID(FM, Fids, SM, RI->getBegin());
AddFID(FM, Fids, SM, RI->getEnd());
}
}
}
// Create a path for the target Plist file.
llvm::sys::Path F(FilePrefix);
F.makeUnique(false, NULL);
// Rename the file with an Plist extension.
llvm::sys::Path H(F);
H.appendSuffix("plist");
F.renamePathOnDisk(H, NULL);
// Now create the plist file.
// Open the file.
std::string ErrMsg;
llvm::raw_fd_ostream o(H.toString().c_str(), false, ErrMsg);
llvm::raw_fd_ostream o(OutputFile.c_str(), false, ErrMsg);
if (!ErrMsg.empty()) {
llvm::errs() << "warning: could not creat file: " << H.toString() << '\n';
llvm::errs() << "warning: could not creat file: " << OutputFile << '\n';
return;
}
// Write the plist header.
o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n";
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n";
// Write the root object: a <dict> containing...
// - "files", an <array> mapping from FIDs to file names
@ -221,16 +201,34 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
" <key>diagnostics</key>\n"
" <array>\n";
for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I)
ReportDiag(o, *I, FM, SM);
for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(),
DE = BatchedDiags.end(); DI!=DE; ++DI) {
o << " <dict>\n"
" <key>path</key>\n";
const PathDiagnostic *D = *DI;
// Create an owning smart pointer for 'D' just so that we auto-free it
// when we exit this method.
llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D));
o << " <array>\n";
for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I)
ReportDiag(o, *I, FM, SM);
o << " </array>\n";
// Output the bug type and bug category.
o << " <key>description</key>\n <string>" << D->getDescription()
<< "</string>\n"
<< " <key>category</key>\n <string>" << D->getCategory()
<< "</string>\n"
<< " </dict>\n";
}
o << " </array>\n";
// Output the bug type and bug category.
o << " <key>description</key>\n <string>" << D->getDescription()
<< "</string>\n"
" <key>category</key>\n <string>" << D->getCategory() << "</string>\n";
// Finish.
o << "</dict>\n</plist>";
}

Просмотреть файл

@ -17,10 +17,20 @@ use warnings;
use Cwd qw/ getcwd abs_path /;
use File::Temp qw/ tempfile /;
use File::Path qw / mkpath /;
use File::Basename;
my $CC = $ENV{'CCC_CC'};
if (!defined $CC) { $CC = "gcc"; }
my $CleanupFile;
my $ResultFile;
# Remove any stale files at exit.
END {
if (defined $CleanupFile && -z $CleanupFile) {
`rm -f $CleanupFile`;
}
}
##----------------------------------------------------------------------------##
# Process Clang Crashes.
##----------------------------------------------------------------------------##
@ -114,9 +124,15 @@ sub Analyze {
print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n";
}
if ($RunAnalyzer and defined($HtmlDir)) {
push @CmdArgs,'-o';
push @CmdArgs,$HtmlDir;
if ($RunAnalyzer) {
if (defined $ResultFile) {
push @CmdArgs,'-o';
push @CmdArgs, $ResultFile;
}
elsif (defined $HtmlDir) {
push @CmdArgs,'-o';
push @CmdArgs, $HtmlDir;
}
}
if (defined $ENV{'CCC_UBI'}) {
@ -430,6 +446,14 @@ if ($Action eq 'compile' or $Action eq 'link') {
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output-" . $OutputFormat;
if ($OutputFormat eq "plist") {
# Change "Output" to be a file.
my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist",
DIR => $HtmlDir);
$ResultFile = $f;
$CleanupFile = $f;
}
}
push @AnalyzeArgs,@CompileOpts;