]> granicus.if.org Git - clang/commitdiff
Updated scan-build:
authorTom Care <tom.care@uqconnect.edu.au>
Thu, 30 Sep 2010 01:12:05 +0000 (01:12 +0000)
committerTom Care <tom.care@uqconnect.edu.au>
Thu, 30 Sep 2010 01:12:05 +0000 (01:12 +0000)
- 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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@115123 91177308-0d34-0410-b5e6-96231b3b80d8

tools/scan-build/scan-build

index 8a7afbb3eaee17ba7faeac1032f2d7127c14158e..425b58e769e9e7a537ad5ec49e986e8c6173183a 100755 (executable)
@@ -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";