scan-build revision 7a334d9ed9ff7426e78a88582207b47b370ec5de
19cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#!/usr/bin/env perl
29cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
39cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#                     The LLVM Compiler Infrastructure
49cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
59cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# This file is distributed under the University of Illinois Open Source
69cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# License. See LICENSE.TXT for details.
79cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
89cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##===----------------------------------------------------------------------===##
99cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# A script designed to wrap a build so that all calls to gcc are intercepted
119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# and piped to the static analyzer.
129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##===----------------------------------------------------------------------===##
149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse strict;
169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse warnings;
1722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenekuse FindBin qw($RealBin);
18a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenekuse Digest::MD5;
197a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekuse File::Basename;
2023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor;
2123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor qw(:constants);
22cd25c13ade3afa829c87ca1ed0ed0d379f426251Ted Kremenekuse Cwd qw/ getcwd abs_path /;
237cba11262458df05951432b54997eb40a35dbf9eTed Kremenekuse Sys::Hostname;
249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Verbose = 0;       # Verbose output from this script.
269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Prog = "scan-build";
27f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildName;
28f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildDate;
299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
300e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $TERM = $ENV{'TERM'};
31c9480dd03522f0bab5fff7d30402cb7ee31117dcTed Kremenekmy $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT
320e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenek                and defined $ENV{'SCAN_BUILD_COLOR'});
3323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
347cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $UserName = HtmlEscape(getpwuid($<) || 'unknown');
357cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HostName = HtmlEscape(hostname() || 'unknown');
367cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDir = HtmlEscape(getcwd());
377cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDirSuffix = basename($CurrentDir);
387cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
39f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginsToLoad;
407cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CmdArgs;
417cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
427cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HtmlTitle;
437cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
447cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $Date = localtime();
457cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
46b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
47b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Diagnostics
48b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
49b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
5023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
5123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
5223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
5323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
5423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
5823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
5923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
60991c54b9b7409656e5593364e065878b5210d556Ted Kremeneksub DiagCrashes {
61991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Dir = shift;
62938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("The analyzer encountered problems on some source files.\n");
63938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("Preprocessed versions of these sources were deposited in '$Dir/failures'.\n");
64991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("Please consider submitting a bug report using these files:\n");
65e2c8663ad2b110712401145b866072bb94108058Nico Weber  Diag ("  http://clang-analyzer.llvm.org/filing_bugs.html\n")
66991c54b9b7409656e5593364e065878b5210d556Ted Kremenek}
67991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
6923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
7023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
7123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
7223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
7323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
7523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
7623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
7823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
7923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
818db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek# Print default checker names
828db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek##----------------------------------------------------------------------------##
838db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek
848db26ce0464c712058ab60b72e2a70c04148020eTed Kremenekif (grep /^--help-checkers$/, @ARGV) {
858db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    my @options = qx($0 -h);
868db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    foreach (@options) {
878db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	next unless /^ \+/;
888db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	s/^\s*//;
898db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	my ($sign, $name, @text) = split ' ', $_;
908db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	print $name, $/ if $sign eq '+';
918db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    }
928db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    exit 1;
938db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek}
948db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek
958db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek##----------------------------------------------------------------------------##
96810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek# Declaration of Clang options.  Populated later.
97b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
99e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $Clang;
100810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangSB;
101810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangCXX;
102810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangVersion;
103fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek
104b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
105fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
108a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
109fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1102a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my $Dir = shift @_;    
111fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
112fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
1133fa3c44d624d2df9ef2649ca1a7efa97d81b36d8Jordan Rose    $Dir = $ENV{'TMPDIR'};
1143fa3c44d624d2df9ef2649ca1a7efa97d81b36d8Jordan Rose    if (!defined $Dir) { $Dir = "/tmp"; }
115fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
116fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
117bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  
118bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  # Chop off any trailing '/' characters.
119bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  while ($Dir =~ /\/$/) { chop $Dir; }
120fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1222a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my @CurrentTime = localtime();  
1239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1269d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1282a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  # Determine the run number.  
1299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1312a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  if (-d $Dir) {    
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
13323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1342a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
1352a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    # Iterate over all files in the specified directory.    
1362a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    my $max = 0;    
1379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
13829da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1412a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    foreach my $f (@FILES) {
142fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
143fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
144fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
145fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
146fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
147fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
1499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
16423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
166fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
167fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
168445fa776d2bc9207c33a9b9ab4afb9513f6b81b0Ted Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
169fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
170fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
173fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
177fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
180fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  my $NewDir;
181fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
182fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
183fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
184fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
185fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$DateString-$RunNumber";
186fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
187fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  system 'mkdir','-p',$NewDir;
188fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  return $NewDir;
1899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
191a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
1929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
1949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
1969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
1979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2019e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek
2029e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek  if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) {
2039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
20723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
21457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
21557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
21657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
21757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
21857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
21923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
220a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
221a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2227ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2237ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
22463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
22523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
226a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
227a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
228a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
229a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
23063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
231a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
23257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
23357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2357a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2367a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2377a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2387a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2397a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2407a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2417a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2427a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2437a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2447a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2457a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2467a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
25020b2bae90c102f405ba70f602c45660ce1cd0c4eTed Kremenek  chop $Prefix while (!($x =~ /^\Q$Prefix/));
2517a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2527a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
26563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
26763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
26863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2707a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
27363c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
27620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2804f2b10b24bab0049020d268382eda144e2aa064cTom Care# AddStatLine - Decode and insert a statistics line into the database.
2814f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
2824f2b10b24bab0049020d268382eda144e2aa064cTom Care
2834f2b10b24bab0049020d268382eda144e2aa064cTom Caresub AddStatLine {
2844f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Line  = shift;
2854f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
2864f2b10b24bab0049020d268382eda144e2aa064cTom Care
2874f2b10b24bab0049020d268382eda144e2aa064cTom Care  print $Line . "\n";
2884f2b10b24bab0049020d268382eda144e2aa064cTom Care
2894f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
2906bdda82234ff106d561dc8c0ce5ca48b97726bbfTed Kremenek      \ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
2914f2b10b24bab0049020d268382eda144e2aa064cTom Care      \ (yes|no)/x;
2924f2b10b24bab0049020d268382eda144e2aa064cTom Care
2934f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($Line !~ $Regex) {
2944f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
2954f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
2964f2b10b24bab0049020d268382eda144e2aa064cTom Care
2974f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Create a hash of the interesting fields
2984f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Row = {
2994f2b10b24bab0049020d268382eda144e2aa064cTom Care    Filename    => $1,
3004f2b10b24bab0049020d268382eda144e2aa064cTom Care    Function    => $2,
3014f2b10b24bab0049020d268382eda144e2aa064cTom Care    Total       => $3,
3024f2b10b24bab0049020d268382eda144e2aa064cTom Care    Unreachable => $4,
3034f2b10b24bab0049020d268382eda144e2aa064cTom Care    Aborted     => $5,
3044f2b10b24bab0049020d268382eda144e2aa064cTom Care    Empty       => $6
3054f2b10b24bab0049020d268382eda144e2aa064cTom Care  };
3064f2b10b24bab0049020d268382eda144e2aa064cTom Care
3074f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Add them to the stats array
3084f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @$Stats, $Row;
3094f2b10b24bab0049020d268382eda144e2aa064cTom Care}
3104f2b10b24bab0049020d268382eda144e2aa064cTom Care
3114f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
3125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3135744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3145744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
31557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
31657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
31757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
31857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
31957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3205744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3215744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3225744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3235744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3254f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
3265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
32757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
32857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
32957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
33057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
33157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
332fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
33357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
33420161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
33557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
33657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
33757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
33857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
33957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
340809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
34120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
342684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
343684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
34423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3455744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3464f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugType        = "";
3474f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugFile        = "";
3484f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugCategory    = "";
3494f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugDescription = "";
3504f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugPathLength  = 1;
3514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugLine        = 0;
352ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
3535744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
354d658e67b438c60fbe3bd1773a3172fd0f082c483Ted Kremenek    last if (/<!-- BUGMETAEND -->/);
355ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
356a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek    if (/<!-- BUGTYPE (.*) -->$/) {
357a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek      $BugType = $1;
3585744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
35922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
360990c2f45e566d8ff097fa90176ba90036892b3cdTed Kremenek      $BugFile = abs_path($1);
3617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
36222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
36422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
36522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
368ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    }
369ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    elsif (/<!-- BUGCATEGORY (.*) -->$/) {
370ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $BugCategory = $1;
37122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3724f2b10b24bab0049020d268382eda144e2aa064cTom Care    elsif (/<!-- BUGDESC (.*) -->$/) {
3734f2b10b24bab0049020d268382eda144e2aa064cTom Care      $BugDescription = $1;
3744f2b10b24bab0049020d268382eda144e2aa064cTom Care    }
3755744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3765744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3775744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
378ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  
379ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  if (!defined $BugCategory) {
380ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    $BugCategory = "Other";
381ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  }
3824f2b10b24bab0049020d268382eda144e2aa064cTom Care
3834f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Don't add internal statistics to the bug reports
3844f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($BugCategory =~ /statistics/i) {
3854f2b10b24bab0049020d268382eda144e2aa064cTom Care    AddStatLine($BugDescription, $Stats);
3864f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
3874f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
3884f2b10b24bab0049020d268382eda144e2aa064cTom Care  
389a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek  push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
39081983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek                 $BugPathLength ];
39122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
39222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
39322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
3943ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek# CopyFiles - Copy resource files to target directory.
39522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
39622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
3973ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremeneksub CopyFiles {
39822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
39922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
400e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek
401e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $JS = Cwd::realpath("$RealBin/sorttable.js");
40222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
40323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
404e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $JS);  
40522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
406e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $JS, "$Dir");
40722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
40823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
40922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
4103ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek    
411e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $CSS = Cwd::realpath("$RealBin/scanview.css");
412e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
4133ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Cannot find 'scanview.css'.\n")
414e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4153ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
416e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $CSS, "$Dir");
4173ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
4183ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
419e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4205744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
4215744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
4225744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
4234f2b10b24bab0049020d268382eda144e2aa064cTom Care# CalcStats - Calculates visitation statistics and returns the string.
4244f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4254f2b10b24bab0049020d268382eda144e2aa064cTom Care
4264f2b10b24bab0049020d268382eda144e2aa064cTom Caresub CalcStats {
4274f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
4284f2b10b24bab0049020d268382eda144e2aa064cTom Care
4294f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalBlocks = 0;
4304f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $UnreachedBlocks = 0;
4314f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFunctions = scalar(@$Stats);
4324f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BlockAborted = 0;
4334f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $WorkListAborted = 0;
4344f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Aborted = 0;
4354f2b10b24bab0049020d268382eda144e2aa064cTom Care
4364f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculate the unique files
4374f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $FilesHash = {};
4384f2b10b24bab0049020d268382eda144e2aa064cTom Care
4394f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $Row (@$Stats) {
4404f2b10b24bab0049020d268382eda144e2aa064cTom Care    $FilesHash->{$Row->{Filename}} = 1;
4414f2b10b24bab0049020d268382eda144e2aa064cTom Care    $TotalBlocks += $Row->{Total};
4424f2b10b24bab0049020d268382eda144e2aa064cTom Care    $UnreachedBlocks += $Row->{Unreachable};
4434f2b10b24bab0049020d268382eda144e2aa064cTom Care    $BlockAborted++ if $Row->{Aborted} eq 'yes';
4444f2b10b24bab0049020d268382eda144e2aa064cTom Care    $WorkListAborted++ if $Row->{Empty} eq 'no';
4454f2b10b24bab0049020d268382eda144e2aa064cTom Care    $Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
4464f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
4474f2b10b24bab0049020d268382eda144e2aa064cTom Care
4484f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFiles = scalar(keys(%$FilesHash));
4494f2b10b24bab0049020d268382eda144e2aa064cTom Care
4504f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculations
4514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
4524f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
4534f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4544f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
4554f2b10b24bab0049020d268382eda144e2aa064cTom Care      $TotalFunctions * 100);
4564f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
4574f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4584f2b10b24bab0049020d268382eda144e2aa064cTom Care
4594f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
4604f2b10b24bab0049020d268382eda144e2aa064cTom Care    . " in $TotalFiles files\n"
4614f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$Aborted functions aborted early ($PercentAborted%)\n"
4624f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
4634f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
4644f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
4654f2b10b24bab0049020d268382eda144e2aa064cTom Care
4664f2b10b24bab0049020d268382eda144e2aa064cTom Care  return $StatsString;
4674f2b10b24bab0049020d268382eda144e2aa064cTom Care}
4684f2b10b24bab0049020d268382eda144e2aa064cTom Care
4694f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
4719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
4729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
473a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
4749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4754f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Dir           = shift;
4764f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BaseDir       = shift;
4774f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $AnalyzerStats = shift;
4789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
479fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
4809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
48223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
483363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
487938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @files = grep { /^report-.*\.html$/ } readdir(DIR);
4889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
4899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
490938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar(@files) == 0 and ! -e "$Dir/failures") {
49123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
49220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
493363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4955744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
496991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  # Scan each report file and build an index.  
4974f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Index;
4984f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Stats;
4994f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
5005744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
501938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  # Scan the failures directory and use the information in the .info files
502d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # to update the common prefix directory.
503938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @failures;
504938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @attributes_ignored;
505938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (-d "$Dir/failures") {
506938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");
507938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
508d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    closedir(DIR);
509938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");        
510938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
511938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    closedir(DIR);
512938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    foreach my $file (@failures) {
513938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
514d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      my $Path = <IN>;
515d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      if (defined $Path) { UpdatePrefix($Path); }
516d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      close IN;
517d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    }    
518d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  }
519d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  
52063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
52163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
52263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
5235744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
5246e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
5256e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
5265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
5275744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
5285744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
5297cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<title>${HtmlTitle}</title>
530f143545ce5ce125e7c1aa6fca9df372bfb604e9cTed Kremenek<link type="text/css" rel="stylesheet" href="scanview.css"/>
53122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
5326e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
5336e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
5346e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
5356e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
5366e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
5376e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
5386e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
5396e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
5406e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5416e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
542ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
5432350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenekfunction CopyCheckedStateToCheckButtons(SummaryCheckButton) {
5442350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  var Inputs = document.getElementsByTagName("input");
5452350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  for ( var i = 0 ; i < Inputs.length; ++i ) {
5462350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    if (Inputs[i].type == "checkbox") {
5472350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      if(Inputs[i] != SummaryCheckButton) {
5482350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].checked = SummaryCheckButton.checked;
5492350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].onclick();
5502350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek	  }
5512350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    }
5522350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  }
5532350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek}
5542350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek
555999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekfunction returnObjById( id ) {
556999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (document.getElementById) 
557999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.getElementById(id);
558999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.all)
559999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.all[id];
560999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.layers) 
561999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.layers[id];
562999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    return returnVar; 
563999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek}
564999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
565999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekvar NumUnchecked = 0;
566999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
5676e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
5686e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
5696e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
570999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (--NumUnchecked == 0) {
571999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek      returnObjById("AllBugsCheck").checked = true;
572999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    }
5736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5746e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
5756e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
576999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    NumUnchecked++;
577999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    returnObjById("AllBugsCheck").checked = false;
5786e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5796e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
5806e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
5811d1abb1dec3d0b7609809d876a16a64a021e96e7Ted Kremenek<!-- SUMMARYENDHEAD -->
5826e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
5836e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
5847cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h1>${HtmlTitle}</h1>
5857cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5867cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<table>
5877cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
5887cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
5897cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
590b4882d50923881d1a01af4d5604b5baaa141cdf9Douglas Gregor<tr><th>Clang Version:</th><td>${ClangVersion}</td></tr>
5917cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Date:</th><td>${Date}</td></tr>
5927cba11262458df05951432b54997eb40a35dbf9eTed KremenekENDTEXT
5937cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5947cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
5957cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if (defined($BuildName) && defined($BuildDate));
5967cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5977cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT <<ENDTEXT;
5987cba11262458df05951432b54997eb40a35dbf9eTed Kremenek</table>
5996e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6006e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
601991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files)) {
602991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Print out the summary table.
603991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my %Totals;
604ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
605991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( @Index ) {
606ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_type = ($row->[2]);
607ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_category = ($row->[1]);
608ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $key = "$bug_category:$bug_type";
609ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
610ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
611ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else { $Totals{$key}->[0]++; }
6126e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
613991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6147cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    print OUT "<h2>Bug Summary</h2>";
615991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
616991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $BuildName) {
617991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
6186e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
619f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
6202350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  my $TotalBugs = scalar(@Index);
6216e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
622ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table>
623ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
624999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek<tr style="font-weight:bold"><td class="SUMM_DESC">All Bugs</td><td class="Q">$TotalBugs</td><td><center><input type="checkbox" id="AllBugsCheck" onClick="CopyCheckedStateToCheckButtons(this);" checked/></center></td></tr>
6256e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6266e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
627ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    my $last_category;
628ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
629ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $key (
630ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      sort {
631ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $x = $Totals{$a};
632ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $y = $Totals{$b};
633ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $res = $x->[1] cmp $y->[1];
634ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res = $x->[2] cmp $y->[2] if ($res == 0);
635ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res
636ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      } keys %Totals ) 
637ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    {
638ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $val = $Totals{$key};
639ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $category = $val->[1];
640ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $last_category or $last_category ne $category) {
641ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $last_category = $category;
642ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
643ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }      
644ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = lc $key;
645ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
646ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr><td class=\"SUMM_DESC\">";
647ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[2];
6482350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      print OUT "</td><td class=\"Q\">";
649ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[0];
650ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
651991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
6526e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6536e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
6546e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6556e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
6566e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
6577cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h2>Reports</h2>
658ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
659ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table class="sortable" style="table-layout:automatic">
660ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr>
661ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td>Bug Group</td>
662ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
663bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
664ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="Q">Line</td>
66581983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek  <td class="Q">Path Length</td>
6662645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
667ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <!-- REPORTBUGCOL -->
668ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek</tr></thead>
669ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<tbody>
6705744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
6719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
672991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $prefix = GetPrefix();
673991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $regex;
674991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFileRegex;
675991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFilePrefix = "File:</td><td>";
6767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
677991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $prefix) { 
678991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $regex = qr/^\Q$prefix\E/is;    
679991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
680991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }    
6817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
682ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
683ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = "$row->[1]:$row->[2]";
684ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x = lc $x;
685ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
6866e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
687991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $ReportFile = $row->[0];
688ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          
689ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr class=\"bt_$x\">";
690ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
691991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT $row->[1];
692ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
693ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
694ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $row->[2];
695ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
696ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
697ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Update the file prefix.      
698ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $fname = $row->[3];
699ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
700991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (defined $regex) {
701991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $fname =~ s/$regex//;
702991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
703991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
704ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
70591639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      print OUT "<td>";      
706ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my @fname = split /\//,$fname;
707ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if ($#fname > 0) {
708ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        while ($#fname >= 0) {
709ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          my $x = shift @fname;
710ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          print OUT $x;
711ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          if ($#fname >= 0) {
712ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek            print OUT "<span class=\"W\"> </span>/";
713ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          }
714ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        }
715ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
716ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else {
717ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT $fname;
71891639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      }      
719ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
720ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
721ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Print out the quantities.
72281983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for my $j ( 4 .. 5 ) {
723ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td class=\"Q\">$row->[$j]</td>";        
724ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
725ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
726991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Print the rest of the columns.
72781983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for (my $j = 6; $j <= $#{$row}; ++$j) {
728ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td>$row->[$j]</td>"
729991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
7307f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
731991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Emit the "View" link.
73268005ddb49b88c2f6cdd88185d72d8b411d2dbc9Ted Kremenek      print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
7333cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
734e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar      # Emit REPORTBUG markers.
735ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
736e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar        
737991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # End the row.
738991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</tr>\n";
739991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
740991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
741ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    print OUT "</tbody>\n</table>\n\n";
742991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  }
743991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
744938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar (@failures) || scalar(@attributes_ignored)) {
745938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    print OUT "<h2>Analyzer Failures</h2>\n";
746938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
747938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @attributes_ignored) {
748938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "The analyzer's parser ignored the following attributes:<p>\n";
749938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
750938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
751938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @attributes_ignored) {
752938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
753938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $attribute = $1;
754938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the attribute file to get the first file that failed.
755938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (!open (ATTR, "$Dir/failures/$file"));
756938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile = <ATTR>;
757938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $ppfile;
758938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close ATTR;
759938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (! -e "$Dir/failures/$ppfile");
760938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the info file and get the name of the source file.
761938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$ppfile.info.txt") or
762938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$ppfile.info.txt\n";
763938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $srcfile = <INFO>;
764938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $srcfile;
765938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close (INFO);
766938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Print the information in the table.
767938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $prefix = GetPrefix();
768938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
769938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "<tr><td>$attribute</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
770938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile_clang = $ppfile;
771938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
772938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
773938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      }
774938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
775938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }
776938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
777938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @failures) {
778938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<p>The analyzer had problems processing the following files:</p>\n";
779938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
780938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
781938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @failures) {
78282a1253077cd0832e4d347062b911cd305ab62d1Ted Kremenek        $file =~ /(.+).info.txt$/;
783991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Get the preprocessed file.
784991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $ppfile = $1;
785991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Open the info file and get the name of the source file.
786938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$file") or
787938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$file\n";
788991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $srcfile = <INFO>;
7895d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $srcfile;
7905d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        my $problem = <INFO>;
7915d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $problem;
792991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        close (INFO);
793991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Print the information in the table.
794d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        my $prefix = GetPrefix();
7959f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
796938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "<tr><td>$problem</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
797ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        my $ppfile_clang = $ppfile;
798ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
799938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
800991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
801938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
802938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }    
803e2c8663ad2b110712401145b866072bb94108058Nico Weber    print OUT "<p>Please consider submitting preprocessed files as <a href=\"http://clang-analyzer.llvm.org/filing_bugs.html\">bug reports</a>. <!-- REPORTCRASHES --> </p>\n";
8045744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
8055744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
806991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  print OUT "</body></html>\n";  
8075744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
8083ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  CopyFiles($Dir);
80920161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
81020161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
81120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
812fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
81320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
8144f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Print statistics
8154f2b10b24bab0049020d268382eda144e2aa064cTom Care  print CalcStats(\@Stats) if $AnalyzerStats;
8164f2b10b24bab0049020d268382eda144e2aa064cTom Care
81723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
818150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
819150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
8205950b3f93a6e8a6ae8bd59a0ef5797e9f88f0bc3Ted Kremenek    Diag("Run 'scan-view $Dir' to examine bug reports.\n");
821150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
822363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
823938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
824991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
825363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
8269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
829dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
830dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
831dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
8326b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
8336b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
8346b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
8356b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
8366b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8376b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
8386b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
8396b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
8406b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
8416b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
8426b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8436b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8446b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
8456b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
8466b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8476b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
8486b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
849cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremeneksub SetEnv {
850cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift @_;
851cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  foreach my $opt ('CC', 'CXX', 'CLANG', 'CLANG_CXX',
852cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS') {
853cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    die "$opt is undefined\n" if (!defined $opt);
854cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{$opt} = $Options->{$opt};
855cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
856cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  foreach my $opt ('CCC_ANALYZER_STORE_MODEL',
857cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_PLUGINS',
858cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_INTERNAL_STATS',
859cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_OUTPUT_FORMAT') {
860cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    my $x = $Options->{$opt};
861cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    if (defined $x) { $ENV{$opt} = $x }
862cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
863cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Verbose = $Options->{'VERBOSE'};
864cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  if ($Verbose >= 2) {
865cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
866cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
867cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  if ($Verbose >= 3) {
868cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{'CCC_ANALYZER_LOG'} = 1;
869cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
870cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek}
871cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
87238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremeneksub RunXcodebuild {
87338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $Args = shift;
87438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $IgnoreErrors = shift;
87538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $CCAnalyzer = shift;
87638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $CXXAnalyzer = shift;
877cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift;
878cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
87938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if ($IgnoreErrors) {
88038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
88138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
88238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
883cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  # Default to old behavior where we insert a bogus compiler.
884cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  SetEnv($Options);
885cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  
88638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # Check if using iPhone SDK 3.0 (simulator).  If so the compiler being
88738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # used should be gcc-4.2.
88838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if (!defined $ENV{"CCC_CC"}) {
88938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
89038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek      if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
89138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek        if (@$Args[$i+1] =~ /^iphonesimulator3/) {
89238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek          $ENV{"CCC_CC"} = "gcc-4.2";
893cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek          $ENV{"CCC_CXX"} = "g++-4.2";
89438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek        }
89538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek      }
89638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    }
89738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
89838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek
89938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # Disable PCH files until clang supports them.
90038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
90138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
90238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
90338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
90438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # (via c++-analyzer) when linking such files.
90538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
90638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek 
90738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  return (system(@$Args) >> 8); 
90838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek}
90938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek
910cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremeneksub RunBuildCommand {  
911dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
9127442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
913dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
9146195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
915524c308506e77e173092e87a0724a27817311428Ted Kremenek  my $CXXAnalyzer = shift;
916cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift;
917dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
9183301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
9193301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
9203301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
9213301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
9223301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
92338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if ($Cmd eq "xcodebuild") {
924cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options);
92538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
92638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
927cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  # Setup the environment.
928cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  SetEnv($Options);
929cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  
93092548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek  if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or 
93192548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?cc[^\/]*$)/ or
93292548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
93305acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek      $Cmd =~ /(.*\/?clang$)/ or 
93492548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
93592548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek
93692548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
93751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CC"} = $1;      
93892548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    }
93992548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek        
940dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
9416195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
942dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
94351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  elsif ($Cmd =~ /(.*\/?g\+\+[^\/]*$)/ or 
94451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+[^\/]*$)/ or
94551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?llvm-g\+\+[^\/]*$)/ or
94605acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek        $Cmd =~ /(.*\/?clang\+\+$)/ or
94751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+-analyzer[^\/]*$)/) {
94851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    if (!($Cmd =~ /c\+\+-analyzer/) and !defined $ENV{"CCC_CXX"}) {
94951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CXX"} = $1;      
95051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    }        
95151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    shift @$Args;
952524c308506e77e173092e87a0724a27817311428Ted Kremenek    unshift @$Args, $CXXAnalyzer;
95351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  }
9547442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
9557442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
9566fba85dc6509069ff7735283464bd02da2da6eebTed Kremenek      AddIfNotPresent($Args, "CC=$CCAnalyzer");
957524c308506e77e173092e87a0724a27817311428Ted Kremenek      AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
9586b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
9598912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
9607442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
9616b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
96287752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek
9635a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
964dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
965dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
966dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
9679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
9689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
9699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
970a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
9719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
9725744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
973a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
9742b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
975f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
976f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
977fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
978f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
979f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
980f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
981f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
9822b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
9832b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
984eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -analyze-headers
9858382cf57b722f130f1a6b45380639871c07271c1Ted Kremenek 
986eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Also analyze functions in #included files.  By default, such functions
987eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   are skipped unless they are called by functions within the main source file.
988eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
989eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -o <output location>
990eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
991eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specifies the output directory for analyzer reports. Subdirectories will be
992eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   created as needed to represent separate "runs" of the analyzer. If this
993eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   option is not specified, a directory is created in /tmp (TMPDIR on Mac OS X)
994eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   to store the reports.
995eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
996eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -h             
997363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
9981262fc4d66584224234691d30d779f8ff004585cTed Kremenek
999eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Display this message.
1000eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1001eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -k
1002eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --keep-going
1003eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek				  
1004eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Add a "keep on going" option to the specified build command. This option
1005eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   currently supports make and xcodebuild. This is a convenience option; one
1006eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   can specify this behavior directly using build options.
1007eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1008eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --html-title [title]
1009eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --html-title=[title]
10102b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1011eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specify the title used on generated HTML pages. If not specified, a default
1012eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   title will be used.
10137cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1014eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -plist
10152c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
1016eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default the output of scan-build is a set of HTML files. This option
1017eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   outputs the results as a set of .plist files.
10182c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
1019eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -plist-html
1020eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1021eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default the output of scan-build is a set of HTML files. This option
1022eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   outputs the results as a set of HTML and .plist files.
1023eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1024eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --status-bugs
1025eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1026eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default, the exit status of scan-build is the same as the executed build
1027eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   command. Specifying this option causes the exit status of scan-build to be 1
1028eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   if it found potential bugs and 0 otherwise.
1029386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
1030eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-cc [compiler path]   
1031eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-cc=[compiler path]
1032eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1033eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   scan-build analyzes a project by interposing a "fake compiler", which
1034eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   executes a real compiler for compilation and the static analyzer for analysis.
1035eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Because of the current implementation of interposition, scan-build does not
1036eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   know what compiler your project normally uses.  Instead, it simply overrides
1037eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   the CC environment variable, and guesses your default compiler.
1038eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   
1039eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   In the future, this interposition mechanism to be improved, but if you need
1040eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   scan-build to use a specific compiler for *compilation* then you can use
1041eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   this option to specify a path to that compiler.
1042eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1043eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-c++ [compiler path]
1044eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-c++=[compiler path]
1045eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1046eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   This is the same as "-use-cc" but for C++ code.
1047eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1048eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -v
1049eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1050eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Enable verbose output from scan-build. A second and third '-v' increases
1051eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   verbosity.
1052f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
1053eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -V
1054eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --view
1055363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
1056eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   View analysis results in a web browser when the build completes.
10577f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
1058be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed KremenekADVANCED OPTIONS:
1059be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
1060eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -no-failure-reports
1061eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1062eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Do not create a 'failures' subdirectory that includes analyzer crash reports
1063eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   and preprocessed source files.
1064b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1065eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -stats
1066eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1067eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Generates visitation statistics for the project being analyzed.
10684f2b10b24bab0049020d268382eda144e2aa064cTom Care
1069eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -maxloop <loop count>
10701e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks 
1071eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specifiy the number of times a block can be visited before giving up.
1072eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Default is 4. Increase for more comprehensive coverage at a cost of speed.
1073eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1074eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -internal-stats
1075eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1076eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Generate internal analyzer statistics.
1077810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 
10785a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek --use-analyzer [Xcode|path to clang] 
10795a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek --use-analyzer=[Xcode|path to clang]
1080810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 
1081810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   scan-build uses the 'clang' executable relative to itself for static
1082810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   analysis. One can override this behavior with this option by using the
1083810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   'clang' packaged with Xcode (on OS X) or from the PATH.
1084810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  
108509fbf297da918760ce33302a3f709a77f43af265Ted KremenekCONTROLLING CHECKERS:
108609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
108709fbf297da918760ce33302a3f709a77f43af265Ted Kremenek A default group of checkers are always run unless explicitly disabled.
108809fbf297da918760ce33302a3f709a77f43af265Ted Kremenek Checkers may be enabled/disabled using the following options:
108909fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
109009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -enable-checker [checker name]
109109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -disable-checker [checker name]
1092f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks 
1093f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna ZaksLOADING CHECKERS:
1094f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1095f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks Loading external checkers using the clang plugin interface:
1096f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1097f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks -load-plugin [plugin library]
1098d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
1099b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1100ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for list of checkers that are enabled.
1101f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1102f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# create a list to load the plugins via the 'Xclang' command line
1103f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# argument
1104f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginLoadCommandline_xclang;
1105f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksforeach my $param ( @PluginsToLoad ) {
1106f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, "-Xclang" );
1107f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, $param );
1108f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks}
1109ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy %EnabledCheckers;
1110ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekforeach my $lang ("c", "objective-c", "objective-c++", "c++") {
1111ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  pipe(FROM_CHILD, TO_PARENT);
1112ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $pid = fork();
1113ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if ($pid == 0) {
1114ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    close FROM_CHILD;
1115ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDOUT,">&", \*TO_PARENT);
1116ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDERR,">&", \*TO_PARENT);
1117f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###'); 
1118ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1119ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(TO_PARENT);
1120ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1121ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    foreach my $val (split /\s+/) {
1122ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $val =~ s/\"//g;
1123ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($val =~ /-analyzer-checker\=([^\s]+)/) {
1124ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $EnabledCheckers{$1} = 1;
1125ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1126ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1127ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1128ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  waitpid($pid,0);
1129ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(FROM_CHILD);
1130ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1131ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1132ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for complete list of checkers.
1133a778d710e2c62d62e0b78d120254764142801196Jordan Roseif (defined $Clang && -x $Clang) {
1134a778d710e2c62d62e0b78d120254764142801196Jordan Rose  pipe(FROM_CHILD, TO_PARENT);
1135a778d710e2c62d62e0b78d120254764142801196Jordan Rose  my $pid = fork();
1136a778d710e2c62d62e0b78d120254764142801196Jordan Rose  if ($pid == 0) {
1137a778d710e2c62d62e0b78d120254764142801196Jordan Rose    close FROM_CHILD;
1138a778d710e2c62d62e0b78d120254764142801196Jordan Rose    open(STDOUT,">&", \*TO_PARENT);
1139a778d710e2c62d62e0b78d120254764142801196Jordan Rose    open(STDERR,">&", \*TO_PARENT);
1140a778d710e2c62d62e0b78d120254764142801196Jordan Rose    exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
1141ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1142a778d710e2c62d62e0b78d120254764142801196Jordan Rose  close(TO_PARENT);
1143a778d710e2c62d62e0b78d120254764142801196Jordan Rose  my $foundCheckers = 0;
1144ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1145a778d710e2c62d62e0b78d120254764142801196Jordan Rose    if (/CHECKERS:/) {
1146a778d710e2c62d62e0b78d120254764142801196Jordan Rose      $foundCheckers = 1;
1147a778d710e2c62d62e0b78d120254764142801196Jordan Rose      last;
114873078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek    }
1149a778d710e2c62d62e0b78d120254764142801196Jordan Rose  }
1150a778d710e2c62d62e0b78d120254764142801196Jordan Rose  if (!$foundCheckers) {
1151a778d710e2c62d62e0b78d120254764142801196Jordan Rose    print "  *** Could not query Clang for the list of available checkers.";
1152a778d710e2c62d62e0b78d120254764142801196Jordan Rose  }
1153a778d710e2c62d62e0b78d120254764142801196Jordan Rose  else {
1154a778d710e2c62d62e0b78d120254764142801196Jordan Rose    print("\nAVAILABLE CHECKERS:\n\n");
1155a778d710e2c62d62e0b78d120254764142801196Jordan Rose    my $skip = 0;
1156a778d710e2c62d62e0b78d120254764142801196Jordan Rose    while(<FROM_CHILD>) {
1157a778d710e2c62d62e0b78d120254764142801196Jordan Rose      if (/experimental/) {
1158a778d710e2c62d62e0b78d120254764142801196Jordan Rose        $skip = 1;
1159a778d710e2c62d62e0b78d120254764142801196Jordan Rose        next;
1160a778d710e2c62d62e0b78d120254764142801196Jordan Rose      }
1161a778d710e2c62d62e0b78d120254764142801196Jordan Rose      if ($skip) {
1162a778d710e2c62d62e0b78d120254764142801196Jordan Rose        next if (!/^\s\s[^\s]/);
1163a778d710e2c62d62e0b78d120254764142801196Jordan Rose        $skip = 0;
1164ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1165a778d710e2c62d62e0b78d120254764142801196Jordan Rose      s/^\s\s//;
1166a778d710e2c62d62e0b78d120254764142801196Jordan Rose      if (/^([^\s]+)/) {
1167a778d710e2c62d62e0b78d120254764142801196Jordan Rose        # Is the checker enabled?
1168a778d710e2c62d62e0b78d120254764142801196Jordan Rose        my $checker = $1;
1169a778d710e2c62d62e0b78d120254764142801196Jordan Rose        my $enabled = 0;
1170a778d710e2c62d62e0b78d120254764142801196Jordan Rose        my $aggregate = "";
1171a778d710e2c62d62e0b78d120254764142801196Jordan Rose        foreach my $domain (split /\./, $checker) {
1172a778d710e2c62d62e0b78d120254764142801196Jordan Rose          $aggregate .= $domain;
1173a778d710e2c62d62e0b78d120254764142801196Jordan Rose          if ($EnabledCheckers{$aggregate}) {
1174a778d710e2c62d62e0b78d120254764142801196Jordan Rose            $enabled =1;
1175a778d710e2c62d62e0b78d120254764142801196Jordan Rose            last;
1176a778d710e2c62d62e0b78d120254764142801196Jordan Rose          }
1177a778d710e2c62d62e0b78d120254764142801196Jordan Rose          # append a dot, if an additional domain is added in the next iteration
1178a778d710e2c62d62e0b78d120254764142801196Jordan Rose          $aggregate .= ".";
1179a778d710e2c62d62e0b78d120254764142801196Jordan Rose        }
1180ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      
1181a778d710e2c62d62e0b78d120254764142801196Jordan Rose        if ($enabled) {
1182a778d710e2c62d62e0b78d120254764142801196Jordan Rose          print " + ";
1183a778d710e2c62d62e0b78d120254764142801196Jordan Rose        }
1184a778d710e2c62d62e0b78d120254764142801196Jordan Rose        else {
1185a778d710e2c62d62e0b78d120254764142801196Jordan Rose          print "   ";
1186a778d710e2c62d62e0b78d120254764142801196Jordan Rose        }
1187ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1188ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      else {
1189ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print "   ";
1190ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1191a778d710e2c62d62e0b78d120254764142801196Jordan Rose      print $_;
1192ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1193a778d710e2c62d62e0b78d120254764142801196Jordan Rose    print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
1194a778d710e2c62d62e0b78d120254764142801196Jordan Rose  }
1195a778d710e2c62d62e0b78d120254764142801196Jordan Rose  waitpid($pid,0);
1196a778d710e2c62d62e0b78d120254764142801196Jordan Rose  close(FROM_CHILD);
1197ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
11987fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1199b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
1200b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
12012b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
12022b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1203363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
120439eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
12055744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
12062b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1207eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek scan-build -o /tmp/myhtmldir make -j4
12082b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
1209eaafdfc7b475937ed194ad729407481054b99be9Ted KremenekThe above example causes analysis reports to be deposited into a subdirectory
1210eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenekof "/tmp/myhtmldir" and to run "make" with the "-j4" option. A different
1211eaafdfc7b475937ed194ad729407481054b99be9Ted Kremeneksubdirectory is created each time scan-build analyzes a project. The analyzer
1212eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenekshould support most parallel builds, but not distributed builds.
12132b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
12142b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
12159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
12169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
12187cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# HtmlEscape - HTML entity encode characters that are special in HTML
12197cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12207cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12217cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub HtmlEscape {
12227cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
12237cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
12247cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $tmp = $arg;
122587f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/&/&amp;/g;
122687f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/</&lt;/g;
122787f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/>/&gt;/g;
12287cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  return $tmp;
12297cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
12307cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12317cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12327cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# ShellEscape - backslash escape characters that are special to the shell
12337cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12347cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12357cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub ShellEscape {
12367cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
12377cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
123887f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
123987f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  return $arg;
12407cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
12417cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12427cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
12449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
12459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1246e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekmy $AnalyzeHeaders = 0;
12479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
12489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
12497f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
1250363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
1251b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
125207c3767be59472e19183c7b51fae76481465cb51Zhongxing Xumy $StoreModel;
1253be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekmy $ConstraintsModel;
12541e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaksmy $InternalStats;
12558d8bc9157fccab6a4089c41cdad9e12045edd736Ted Kremenekmy $OutputFormat = "html";
12564f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $AnalyzerStats = 0;
12574f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $MaxLoop = 0;
12589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
12609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1261a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
12629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
12639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1264ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1265ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $displayHelp = 0;
1266810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $AnalyzerDiscoveryMethod;
1267ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
12689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
12699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
12719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
12739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12742f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
1275ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $displayHelp = 1;
1276ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    shift @ARGV;
1277ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    next;
12789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1280e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  if ($arg eq '-analyze-headers') {
1281e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    shift @ARGV;    
1282e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    $AnalyzeHeaders = 1;
1283e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    next;
1284e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  }
1285e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
12869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
12879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
12889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
12899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
129023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
12919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
12929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1293db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # Construct an absolute path.  Uses the current working directory
1294db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # as a base if the original path was not absolute.
1295db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    $HtmlDir = abs_path(shift @ARGV);
1296db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    
12979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
12989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12997cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13007cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--html-title(=(.+))?$/) {
13017cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    shift @ARGV;
13027cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1303278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq '') {
13047cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      if (!@ARGV) {
13057cba11262458df05951432b54997eb40a35dbf9eTed Kremenek        DieDiag("'--html-title' option requires a string.\n");
13067cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      }
13077cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13087cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = shift @ARGV;
13097cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    } else {
13107cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = $2;
13117cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    }
13127cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13137cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    next;
13147cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  }
13159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13162b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
13179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
13199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13217fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1322f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
1323f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
1324f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
1325f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1326278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1327f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
1328f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
1329f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
1330f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
1331f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1332f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
1333f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
1334f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1335f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1336f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
1337f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
1338f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
1339f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
13407cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
1341386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
134251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    my $cxx;    
1343386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
1344278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1345386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
1346386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
1347386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
134851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = shift @ARGV;
1349386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
1350386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
135151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = $2;
1352386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
135351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    
135451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    $ENV{"CCC_CXX"} = $cxx;
1355386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
1356386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
1357386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
13589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
13599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
13619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13647f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
13657f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
13667f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
13677f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
13687f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
13697f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
1370363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
1371363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
1372363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
1373363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
1374363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
137507c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu
137607c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  if ($arg eq "-store") {
137707c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    shift @ARGV;
1378be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $StoreModel = shift @ARGV;
1379be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    next;
1380be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  }
1381be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  
1382be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  if ($arg eq "-constraints") {
1383be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    shift @ARGV;
1384be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $ConstraintsModel = shift @ARGV;
138507c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    next;
138607c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  }
13871e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks
13881e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks  if ($arg eq "-internal-stats") {
13891e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    shift @ARGV;
13901e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    $InternalStats = 1;
13911e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    next;
13921e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks  }
1393363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
1394db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  if ($arg eq "-plist") {
1395db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    shift @ARGV;
1396db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    $OutputFormat = "plist";
1397db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    next;
1398db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
13997753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  if ($arg eq "-plist-html") {
14007753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    shift @ARGV;
14017753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    $OutputFormat = "plist-html";
14027753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    next;
14037753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  }
1404e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  
1405e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  if ($arg eq "-no-failure-reports") {
1406e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    $ENV{"CCC_REPORT_FAILURES"} = 0;
1407e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    next;
1408e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  }
14094f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-stats") {
14104f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
14114f2b10b24bab0049020d268382eda144e2aa064cTom Care    $AnalyzerStats = 1;
14124f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
14134f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
14144f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-maxloop") {
14154f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
14164f2b10b24bab0049020d268382eda144e2aa064cTom Care    $MaxLoop = shift @ARGV;
14174f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
14184f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
141909fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-enable-checker") {
142009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
142109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-checker", shift @ARGV;
142209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
142309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
142409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-disable-checker") {
142509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
142609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV;
142709fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
142809fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
1429f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  if ($arg eq "-load-plugin") {
1430f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    shift @ARGV;
1431f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    push @PluginsToLoad, "-load", shift @ARGV;
1432f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    next;
1433f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  }
14345a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek  if ($arg eq "--use-analyzer") {
1435810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 	shift @ARGV;
1436810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  	$AnalyzerDiscoveryMethod = shift @ARGV;
1437810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	next;
1438810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
14395a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek  if ($arg =~ /^--use-analyzer=(.+)$/) {
1440810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    shift @ARGV;
1441810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	$AnalyzerDiscoveryMethod = $1;
1442810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	next;
1443810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1444f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  
144523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
14460062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
14479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
14489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
14499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1450ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!@ARGV and $displayHelp == 0) {
145123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
1452ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  $displayHelp = 1;
1453ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1454ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1455810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek# Find 'clang'
1456810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekif (!defined $AnalyzerDiscoveryMethod) {
1457810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  $Clang = Cwd::realpath("$RealBin/bin/clang");
1458810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  if (!defined $Clang || ! -x $Clang) {
1459810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = Cwd::realpath("$RealBin/clang");
1460810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1461810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  if (!defined $Clang || ! -x $Clang) {
1462a778d710e2c62d62e0b78d120254764142801196Jordan Rose    if (!$displayHelp) {
1463a778d710e2c62d62e0b78d120254764142801196Jordan Rose      DieDiag("error: Cannot find an executable 'clang' relative to scan-build." .
1464a778d710e2c62d62e0b78d120254764142801196Jordan Rose   	          "  Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n");
1465a778d710e2c62d62e0b78d120254764142801196Jordan Rose    }
1466810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1467810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek} 
1468810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekelse {  
14690d3a3fd7211a1b368d1f8c0d7ca1cfd40d31a0eaTed Kremenek  if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) {
1470810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	my $xcrun = `which xcrun`;
1471810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    chomp $xcrun;
1472810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	if ($xcrun eq "") {
1473810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  	  DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n");
1474810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	}
1475810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = `$xcrun -toolchain XcodeDefault -find clang`;
1476810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    chomp $Clang;  
1477810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    if ($Clang eq "") {
1478810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek      DieDiag("No 'clang' executable found by 'xcrun'\n"); 
1479810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    }
1480810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1481810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  else {
1482810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = Cwd::realpath($AnalyzerDiscoveryMethod);
1483810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	if (! -x $Clang) {
1484810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   	  DieDiag("Cannot find an executable clang at '$Clang'\n");
1485810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	}
1486810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1487810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek}
1488810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek
1489a778d710e2c62d62e0b78d120254764142801196Jordan Roseif ($displayHelp) {
1490a778d710e2c62d62e0b78d120254764142801196Jordan Rose  DisplayHelp();
1491a778d710e2c62d62e0b78d120254764142801196Jordan Rose  exit 1;
1492a778d710e2c62d62e0b78d120254764142801196Jordan Rose}
1493a778d710e2c62d62e0b78d120254764142801196Jordan Rose
1494810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX = $Clang;
1495810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX =~ s/\-\d+\.\d+$//;
1496810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX .= "++";
1497810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangVersion = HtmlEscape(`$Clang --version`);
1498810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek
1499ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine where results go.
15007cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
15017cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
15027cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  unless (defined($HtmlTitle));
1503386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
15049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
1505684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
1506a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
15079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1508ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine the location of ccc-analyzer.
150951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $AbsRealBin = Cwd::realpath($RealBin);
151051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $Cmd = "$AbsRealBin/libexec/ccc-analyzer";
151151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $CmdCXX = "$AbsRealBin/libexec/c++-analyzer";
151251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek
1513ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenekif (!defined $Cmd || ! -x $Cmd) {
151451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $Cmd = "$AbsRealBin/ccc-analyzer";
15156b89636db873142f562cf576df9bc195c5b8674bTed Kremenek  DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
1516ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenek}
151751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekif (!defined $CmdCXX || ! -x $CmdCXX) {
151851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $CmdCXX = "$AbsRealBin/c++-analyzer";
151951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
152051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek}
1521f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
1522810e6229e59796f8109e94e4a469a2dc17cf3e6dTed KremenekDiag("Using '$Clang' for static analysis\n");
15230b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
1524ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted KremenekSetHtmlEnv(\@ARGV, $HtmlDir);
1525cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekif ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; }
1526cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekif ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; }
1527be92debbf1e9c38b1ae8a4a9c30377b24196ca73Ted Kremenekif ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; }
1528cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
1529cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek# Delay setting up other environment variables in case we can do true
1530cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek# interposition.
1531cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $CCC_ANALYZER_ANALYSIS = join ' ',@AnalysesToRun;
1532cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $CCC_ANALYZER_PLUGINS = join ' ',@PluginsToLoad;
1533cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy %Options = (
1534cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CC' => $Cmd,
1535cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CXX' => $CmdCXX,
1536cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CLANG' => $Clang,
1537cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CLANG_CXX' => $ClangCXX,
1538cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'VERBOSE' => $Verbose,
1539cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CCC_ANALYZER_ANALYSIS' => $CCC_ANALYZER_ANALYSIS,
1540cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CCC_ANALYZER_PLUGINS' => $CCC_ANALYZER_PLUGINS,
1541cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'OUTPUT_DIR' => $HtmlDir
1542cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek);
1543f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
15443cab2b1c3798f2a6aa3526875801a02aebf6fc1dZhongxing Xuif (defined $StoreModel) {
1545cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
154607c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu}
1547be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekif (defined $ConstraintsModel) {
1548cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
1549be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek}
15501e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaksif (defined $InternalStats) {
1551cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_INTERNAL_STATS'} = 1;
15521e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks}
1553db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenekif (defined $OutputFormat) {
1554cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
1555db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek}
1556db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
15579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
1558cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX,
1559cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                                \%Options);
15609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
15617753b352366778d01c5cda4117356f181d3dd468Ted Kremenekif (defined $OutputFormat) {
15621182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  if ($OutputFormat =~ /plist/) {
15631182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis run complete.\n";
15641182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
15651182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  }
15667a334d9ed9ff7426e78a88582207b47b370ec5deTed Kremenek  if ($OutputFormat =~ /html/) {
15677753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    # Postprocess the HTML directory.
15684f2b10b24bab0049020d268382eda144e2aa064cTom Care    my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
15697753b352366778d01c5cda4117356f181d3dd468Ted Kremenek
15707753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ViewResults and -r "$HtmlDir/index.html") {
15717753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Analysis run complete.\n";
15727753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
15737753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      my $ScanView = Cwd::realpath("$RealBin/scan-view");
15747753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      if (! -x $ScanView) { $ScanView = "scan-view"; }
15757753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exec $ScanView, "$HtmlDir";
15767753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1577db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
15787753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ExitStatusFoundBugs) {
15797753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 1 if ($NumBugs > 0);
15807753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 0;
15817753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1582db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
1583363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
1584363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
15855656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
15865656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
1587