Updated scan-build:
- Idempotent operations are on by default, to match --analyze in the driver. - Integrated stats calculation based on parsing warnings emitted with the -analyzer-stats flag. The new -stats flag enables this. - New -maxloop flag to pass down a maxloop value to the analyzer. llvm-svn: 115123
This commit is contained in:
parent
c768287968
commit
ea7c48ccf7
|
@ -120,7 +120,8 @@ my %AnalysesDefaultEnabled = (
|
|||
# Do not enable the missing -dealloc check by default.
|
||||
# '-analyzer-check-objc-missing-dealloc' => 1,
|
||||
'-analyzer-check-objc-unused-ivars' => 1,
|
||||
'-analyzer-check-security-syntactic' => 1
|
||||
'-analyzer-check-security-syntactic' => 1,
|
||||
'-analyzer-check-idempotent-operations' => 1
|
||||
);
|
||||
|
||||
##----------------------------------------------------------------------------##
|
||||
|
@ -303,6 +304,38 @@ sub UpdateInFilePath {
|
|||
system("mv", "$fname.tmp", $fname);
|
||||
}
|
||||
|
||||
##----------------------------------------------------------------------------##
|
||||
# AddStatLine - Decode and insert a statistics line into the database.
|
||||
##----------------------------------------------------------------------------##
|
||||
|
||||
sub AddStatLine {
|
||||
my $Line = shift;
|
||||
my $Stats = shift;
|
||||
|
||||
print $Line . "\n";
|
||||
|
||||
my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
|
||||
\ CFGBlocks:\ (\d+)\ \|\ Aborted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
|
||||
\ (yes|no)/x;
|
||||
|
||||
if ($Line !~ $Regex) {
|
||||
return;
|
||||
}
|
||||
|
||||
# Create a hash of the interesting fields
|
||||
my $Row = {
|
||||
Filename => $1,
|
||||
Function => $2,
|
||||
Total => $3,
|
||||
Unreachable => $4,
|
||||
Aborted => $5,
|
||||
Empty => $6
|
||||
};
|
||||
|
||||
# Add them to the stats array
|
||||
push @$Stats, $Row;
|
||||
}
|
||||
|
||||
##----------------------------------------------------------------------------##
|
||||
# ScanFile - Scan a report file for various identifying attributes.
|
||||
##----------------------------------------------------------------------------##
|
||||
|
@ -317,6 +350,7 @@ sub ScanFile {
|
|||
my $Index = shift;
|
||||
my $Dir = shift;
|
||||
my $FName = shift;
|
||||
my $Stats = shift;
|
||||
|
||||
# Compute a digest for the report file. Determine if we have already
|
||||
# scanned a file that looks just like it.
|
||||
|
@ -337,11 +371,12 @@ sub ScanFile {
|
|||
# Scan the report file for tags.
|
||||
open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
|
||||
|
||||
my $BugType = "";
|
||||
my $BugFile = "";
|
||||
my $BugCategory;
|
||||
my $BugPathLength = 1;
|
||||
my $BugLine = 0;
|
||||
my $BugType = "";
|
||||
my $BugFile = "";
|
||||
my $BugCategory = "";
|
||||
my $BugDescription = "";
|
||||
my $BugPathLength = 1;
|
||||
my $BugLine = 0;
|
||||
|
||||
while (<IN>) {
|
||||
last if (/<!-- BUGMETAEND -->/);
|
||||
|
@ -362,6 +397,9 @@ sub ScanFile {
|
|||
elsif (/<!-- BUGCATEGORY (.*) -->$/) {
|
||||
$BugCategory = $1;
|
||||
}
|
||||
elsif (/<!-- BUGDESC (.*) -->$/) {
|
||||
$BugDescription = $1;
|
||||
}
|
||||
}
|
||||
|
||||
close(IN);
|
||||
|
@ -369,7 +407,13 @@ sub ScanFile {
|
|||
if (!defined $BugCategory) {
|
||||
$BugCategory = "Other";
|
||||
}
|
||||
|
||||
|
||||
# Don't add internal statistics to the bug reports
|
||||
if ($BugCategory =~ /statistics/i) {
|
||||
AddStatLine($BugDescription, $Stats);
|
||||
return;
|
||||
}
|
||||
|
||||
push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
|
||||
$BugPathLength ];
|
||||
}
|
||||
|
@ -403,14 +447,62 @@ sub CopyFiles {
|
|||
if (! -r $CSS);
|
||||
}
|
||||
|
||||
##----------------------------------------------------------------------------##
|
||||
# CalcStats - Calculates visitation statistics and returns the string.
|
||||
##----------------------------------------------------------------------------##
|
||||
|
||||
sub CalcStats {
|
||||
my $Stats = shift;
|
||||
|
||||
my $TotalBlocks = 0;
|
||||
my $UnreachedBlocks = 0;
|
||||
my $TotalFunctions = scalar(@$Stats);
|
||||
my $BlockAborted = 0;
|
||||
my $WorkListAborted = 0;
|
||||
my $Aborted = 0;
|
||||
|
||||
# Calculate the unique files
|
||||
my $FilesHash = {};
|
||||
|
||||
foreach my $Row (@$Stats) {
|
||||
$FilesHash->{$Row->{Filename}} = 1;
|
||||
$TotalBlocks += $Row->{Total};
|
||||
$UnreachedBlocks += $Row->{Unreachable};
|
||||
$BlockAborted++ if $Row->{Aborted} eq 'yes';
|
||||
$WorkListAborted++ if $Row->{Empty} eq 'no';
|
||||
$Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
|
||||
}
|
||||
|
||||
my $TotalFiles = scalar(keys(%$FilesHash));
|
||||
|
||||
# Calculations
|
||||
my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
|
||||
my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
|
||||
* 100);
|
||||
my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
|
||||
$TotalFunctions * 100);
|
||||
my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
|
||||
* 100);
|
||||
|
||||
my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
|
||||
. " in $TotalFiles files\n"
|
||||
. "$Aborted functions aborted early ($PercentAborted%)\n"
|
||||
. "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
|
||||
. "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
|
||||
. "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
|
||||
|
||||
return $StatsString;
|
||||
}
|
||||
|
||||
##----------------------------------------------------------------------------##
|
||||
# Postprocess - Postprocess the results of an analysis scan.
|
||||
##----------------------------------------------------------------------------##
|
||||
|
||||
sub Postprocess {
|
||||
|
||||
my $Dir = shift;
|
||||
my $BaseDir = shift;
|
||||
my $Dir = shift;
|
||||
my $BaseDir = shift;
|
||||
my $AnalyzerStats = shift;
|
||||
|
||||
die "No directory specified." if (!defined $Dir);
|
||||
|
||||
|
@ -430,8 +522,9 @@ sub Postprocess {
|
|||
}
|
||||
|
||||
# Scan each report file and build an index.
|
||||
my @Index;
|
||||
foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
|
||||
my @Index;
|
||||
my @Stats;
|
||||
foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
|
||||
|
||||
# Scan the failures directory and use the information in the .info files
|
||||
# to update the common prefix directory.
|
||||
|
@ -745,6 +838,9 @@ ENDTEXT
|
|||
system("chmod", "755", $Dir);
|
||||
if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
|
||||
|
||||
# Print statistics
|
||||
print CalcStats(\@Stats) if $AnalyzerStats;
|
||||
|
||||
my $Num = scalar(@Index);
|
||||
Diag("$Num bugs found.\n");
|
||||
if ($Num > 0 && -r "$Dir/index.html") {
|
||||
|
@ -930,6 +1026,12 @@ ADVANCED OPTIONS:
|
|||
-no-failure-reports - Do not create a 'failures' subdirectory that includes
|
||||
analyzer crash reports and preprocessed source files.
|
||||
|
||||
-stats - Generates visitation statistics for the project being analyzed.
|
||||
|
||||
-maxloop N - specifiy the number of times a block can be visited before giving
|
||||
up. Default is 3. Increase for more comprehensive coverage at a
|
||||
cost of speed.
|
||||
|
||||
AVAILABLE ANALYSES (multiple analyses may be specified):
|
||||
|
||||
ENDTEXT
|
||||
|
@ -1004,6 +1106,8 @@ my @AnalysesToRun;
|
|||
my $StoreModel;
|
||||
my $ConstraintsModel;
|
||||
my $OutputFormat = "html";
|
||||
my $AnalyzerStats = 0;
|
||||
my $MaxLoop = 0;
|
||||
|
||||
if (!@ARGV) {
|
||||
DisplayHelp();
|
||||
|
@ -1156,6 +1260,16 @@ while (@ARGV) {
|
|||
$ENV{"CCC_REPORT_FAILURES"} = 0;
|
||||
next;
|
||||
}
|
||||
if ($arg eq "-stats") {
|
||||
shift @ARGV;
|
||||
$AnalyzerStats = 1;
|
||||
next;
|
||||
}
|
||||
if ($arg eq "-maxloop") {
|
||||
shift @ARGV;
|
||||
$MaxLoop = shift @ARGV;
|
||||
next;
|
||||
}
|
||||
|
||||
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
|
||||
|
||||
|
@ -1220,6 +1334,14 @@ if ($AnalyzeHeaders) {
|
|||
push @AnalysesToRun,"-analyzer-opt-analyze-headers";
|
||||
}
|
||||
|
||||
if ($AnalyzerStats) {
|
||||
push @AnalysesToRun, '-analyzer-stats';
|
||||
}
|
||||
|
||||
if ($MaxLoop > 0) {
|
||||
push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop;
|
||||
}
|
||||
|
||||
$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
|
||||
|
||||
if (defined $StoreModel) {
|
||||
|
@ -1244,7 +1366,7 @@ if (defined $OutputFormat) {
|
|||
}
|
||||
elsif ($OutputFormat =~ /html/) {
|
||||
# Postprocess the HTML directory.
|
||||
my $NumBugs = Postprocess($HtmlDir, $BaseDir);
|
||||
my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
|
||||
|
||||
if ($ViewResults and -r "$HtmlDir/index.html") {
|
||||
Diag "Analysis run complete.\n";
|
||||
|
|
Loading…
Reference in New Issue