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;
209d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenekuse File::Find;
2123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor;
2223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor qw(:constants);
23cd25c13ade3afa829c87ca1ed0ed0d379f426251Ted Kremenekuse Cwd qw/ getcwd abs_path /;
247cba11262458df05951432b54997eb40a35dbf9eTed Kremenekuse Sys::Hostname;
259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Verbose = 0;       # Verbose output from this script.
279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Prog = "scan-build";
28f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildName;
29f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildDate;
309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
310e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $TERM = $ENV{'TERM'};
32c9480dd03522f0bab5fff7d30402cb7ee31117dcTed Kremenekmy $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT
330e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenek                and defined $ENV{'SCAN_BUILD_COLOR'});
3423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
357cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $UserName = HtmlEscape(getpwuid($<) || 'unknown');
367cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HostName = HtmlEscape(hostname() || 'unknown');
377cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDir = HtmlEscape(getcwd());
387cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDirSuffix = basename($CurrentDir);
397cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
40f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginsToLoad;
417cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CmdArgs;
427cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
437cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HtmlTitle;
447cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
457cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $Date = localtime();
467cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
47b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
48b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Diagnostics
49b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
50b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
5123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
5223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
5323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
5423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
5823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
5923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
6023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
61991c54b9b7409656e5593364e065878b5210d556Ted Kremeneksub DiagCrashes {
62991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Dir = shift;
63938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("The analyzer encountered problems on some source files.\n");
64938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("Preprocessed versions of these sources were deposited in '$Dir/failures'.\n");
65991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("Please consider submitting a bug report using these files:\n");
66e2c8663ad2b110712401145b866072bb94108058Nico Weber  Diag ("  http://clang-analyzer.llvm.org/filing_bugs.html\n")
67991c54b9b7409656e5593364e065878b5210d556Ted Kremenek}
68991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
7023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
7123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
7223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
7323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
7423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
7623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
7723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
7923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
8023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
828db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek# Print default checker names
838db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek##----------------------------------------------------------------------------##
848db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek
858db26ce0464c712058ab60b72e2a70c04148020eTed Kremenekif (grep /^--help-checkers$/, @ARGV) {
868db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    my @options = qx($0 -h);
878db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    foreach (@options) {
888db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	next unless /^ \+/;
898db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	s/^\s*//;
908db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	my ($sign, $name, @text) = split ' ', $_;
918db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	print $name, $/ if $sign eq '+';
928db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    }
938db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    exit 1;
948db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek}
958db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek
968db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek##----------------------------------------------------------------------------##
97810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek# Declaration of Clang options.  Populated later.
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
99b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
100e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $Clang;
101810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangSB;
102810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangCXX;
103810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangVersion;
104fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek
105b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
106fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
109a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
110fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1112a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my $Dir = shift @_;    
112fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
113fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
1143fa3c44d624d2df9ef2649ca1a7efa97d81b36d8Jordan Rose    $Dir = $ENV{'TMPDIR'};
1153fa3c44d624d2df9ef2649ca1a7efa97d81b36d8Jordan Rose    if (!defined $Dir) { $Dir = "/tmp"; }
116fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
117fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
118bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  
119bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  # Chop off any trailing '/' characters.
120bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  while ($Dir =~ /\/$/) { chop $Dir; }
121fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1232a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my @CurrentTime = localtime();  
1249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1279d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1292a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  # Determine the run number.  
1309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1322a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  if (-d $Dir) {    
1339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
13423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1352a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
1362a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    # Iterate over all files in the specified directory.    
1372a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    my $max = 0;    
1389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
13929da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1422a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    foreach my $f (@FILES) {
143fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
144fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
145fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
146fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
147fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
148fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
1509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
16523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
167fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
168fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
169445fa776d2bc9207c33a9b9ab4afb9513f6b81b0Ted Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
170fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
171fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
174fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
178fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
181fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  my $NewDir;
182fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
183fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
184fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
185fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
186fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$DateString-$RunNumber";
187fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
188fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  system 'mkdir','-p',$NewDir;
189fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  return $NewDir;
1909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
192a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
1939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
1979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2029e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek
2039e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek  if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) {
2049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
20823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
21557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
21657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
21757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
21857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
21957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
22023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
221a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
222a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2237ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2247ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
22563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
22623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
227a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
228a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
229a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
230a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
23163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
232a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
23357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
23457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2367a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2377a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2387a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2397a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2407a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2417a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2427a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2437a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2447a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2457a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2467a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2507a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
25120b2bae90c102f405ba70f602c45660ce1cd0c4eTed Kremenek  chop $Prefix while (!($x =~ /^\Q$Prefix/));
2527a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
26663c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
26863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
26963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2707a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
27463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
27720161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2814f2b10b24bab0049020d268382eda144e2aa064cTom Care# AddStatLine - Decode and insert a statistics line into the database.
2824f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
2834f2b10b24bab0049020d268382eda144e2aa064cTom Care
2844f2b10b24bab0049020d268382eda144e2aa064cTom Caresub AddStatLine {
2854f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Line  = shift;
2864f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
2874a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose  my $File  = shift;
2884f2b10b24bab0049020d268382eda144e2aa064cTom Care
2894f2b10b24bab0049020d268382eda144e2aa064cTom Care  print $Line . "\n";
2904f2b10b24bab0049020d268382eda144e2aa064cTom Care
2914a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose  my $Regex = qr/(.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
2926bdda82234ff106d561dc8c0ce5ca48b97726bbfTed Kremenek      \ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
2934f2b10b24bab0049020d268382eda144e2aa064cTom Care      \ (yes|no)/x;
2944f2b10b24bab0049020d268382eda144e2aa064cTom Care
2954f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($Line !~ $Regex) {
2964f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
2974f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
2984f2b10b24bab0049020d268382eda144e2aa064cTom Care
2994f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Create a hash of the interesting fields
3004f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Row = {
3014a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    Filename    => $File,
3024a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    Function    => $1,
3034a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    Total       => $2,
3044a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    Unreachable => $3,
3054a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    Aborted     => $4,
3064a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    Empty       => $5
3074f2b10b24bab0049020d268382eda144e2aa064cTom Care  };
3084f2b10b24bab0049020d268382eda144e2aa064cTom Care
3094f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Add them to the stats array
3104f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @$Stats, $Row;
3114f2b10b24bab0049020d268382eda144e2aa064cTom Care}
3124f2b10b24bab0049020d268382eda144e2aa064cTom Care
3134f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
3145744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3155744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3165744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
31757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
31857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
31957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
32057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
32157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3225744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3235744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3274f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
3285744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
32957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
33057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
33157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
33257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
33357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
334fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
33557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
33620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
33757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
33857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
33957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
34057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
34157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
342809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
34320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
344684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
345684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
34623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3475744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3484f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugType        = "";
3494f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugFile        = "";
3504f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugCategory    = "";
3514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugDescription = "";
3524f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugPathLength  = 1;
3534f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugLine        = 0;
354ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
3555744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
356d658e67b438c60fbe3bd1773a3172fd0f082c483Ted Kremenek    last if (/<!-- BUGMETAEND -->/);
357ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
358a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek    if (/<!-- BUGTYPE (.*) -->$/) {
359a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek      $BugType = $1;
3605744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
36122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
362990c2f45e566d8ff097fa90176ba90036892b3cdTed Kremenek      $BugFile = abs_path($1);
3637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
36422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
36622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
36922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
370ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    }
371ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    elsif (/<!-- BUGCATEGORY (.*) -->$/) {
372ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $BugCategory = $1;
37322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3744f2b10b24bab0049020d268382eda144e2aa064cTom Care    elsif (/<!-- BUGDESC (.*) -->$/) {
3754f2b10b24bab0049020d268382eda144e2aa064cTom Care      $BugDescription = $1;
3764f2b10b24bab0049020d268382eda144e2aa064cTom Care    }
3775744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3785744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3795744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
380ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  
381ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  if (!defined $BugCategory) {
382ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    $BugCategory = "Other";
383ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  }
3844f2b10b24bab0049020d268382eda144e2aa064cTom Care
3854f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Don't add internal statistics to the bug reports
3864f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($BugCategory =~ /statistics/i) {
3874a374f9a58a5b350ec2e4123b20c9884ed1f5f15Jordan Rose    AddStatLine($BugDescription, $Stats, $BugFile);
3884f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
3894f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
3904f2b10b24bab0049020d268382eda144e2aa064cTom Care  
391a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek  push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
39281983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek                 $BugPathLength ];
39322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
39422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
39522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
3963ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek# CopyFiles - Copy resource files to target directory.
39722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
39822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
3993ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremeneksub CopyFiles {
40022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
40122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
402e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek
403e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $JS = Cwd::realpath("$RealBin/sorttable.js");
40422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
40523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
406e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $JS);  
40722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
408e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $JS, "$Dir");
40922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
41023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
41122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
4123ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek    
413e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $CSS = Cwd::realpath("$RealBin/scanview.css");
414e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
4153ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Cannot find 'scanview.css'.\n")
416e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4173ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
418e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $CSS, "$Dir");
4193ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
4203ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
421e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4225744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
4235744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
4245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
4254f2b10b24bab0049020d268382eda144e2aa064cTom Care# CalcStats - Calculates visitation statistics and returns the string.
4264f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4274f2b10b24bab0049020d268382eda144e2aa064cTom Care
4284f2b10b24bab0049020d268382eda144e2aa064cTom Caresub CalcStats {
4294f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
4304f2b10b24bab0049020d268382eda144e2aa064cTom Care
4314f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalBlocks = 0;
4324f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $UnreachedBlocks = 0;
4334f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFunctions = scalar(@$Stats);
4344f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BlockAborted = 0;
4354f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $WorkListAborted = 0;
4364f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Aborted = 0;
4374f2b10b24bab0049020d268382eda144e2aa064cTom Care
4384f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculate the unique files
4394f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $FilesHash = {};
4404f2b10b24bab0049020d268382eda144e2aa064cTom Care
4414f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $Row (@$Stats) {
4424f2b10b24bab0049020d268382eda144e2aa064cTom Care    $FilesHash->{$Row->{Filename}} = 1;
4434f2b10b24bab0049020d268382eda144e2aa064cTom Care    $TotalBlocks += $Row->{Total};
4444f2b10b24bab0049020d268382eda144e2aa064cTom Care    $UnreachedBlocks += $Row->{Unreachable};
4454f2b10b24bab0049020d268382eda144e2aa064cTom Care    $BlockAborted++ if $Row->{Aborted} eq 'yes';
4464f2b10b24bab0049020d268382eda144e2aa064cTom Care    $WorkListAborted++ if $Row->{Empty} eq 'no';
4474f2b10b24bab0049020d268382eda144e2aa064cTom Care    $Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
4484f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
4494f2b10b24bab0049020d268382eda144e2aa064cTom Care
4504f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFiles = scalar(keys(%$FilesHash));
4514f2b10b24bab0049020d268382eda144e2aa064cTom Care
4524f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculations
4534f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
4544f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
4554f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4564f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
4574f2b10b24bab0049020d268382eda144e2aa064cTom Care      $TotalFunctions * 100);
4584f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
4594f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4604f2b10b24bab0049020d268382eda144e2aa064cTom Care
4614f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
4624f2b10b24bab0049020d268382eda144e2aa064cTom Care    . " in $TotalFiles files\n"
4634f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$Aborted functions aborted early ($PercentAborted%)\n"
4644f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
4654f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
4664f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
4674f2b10b24bab0049020d268382eda144e2aa064cTom Care
4684f2b10b24bab0049020d268382eda144e2aa064cTom Care  return $StatsString;
4694f2b10b24bab0049020d268382eda144e2aa064cTom Care}
4704f2b10b24bab0049020d268382eda144e2aa064cTom Care
4714f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
4739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
4749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
4759d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenekmy @filesFound;
4769d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenekmy $baseDir;
4779d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremeneksub FileWanted { 
4789d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek    my $baseDirRegEx = quotemeta $baseDir;
4799d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek    my $file = $File::Find::name;
4809d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek    if ($file =~ /report-.*\.html$/) {
4819d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek       my $relative_file = $file;
4829d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek       $relative_file =~ s/$baseDirRegEx//g;
4839d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek       push @filesFound, $relative_file;
4849d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek    }
4859d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek}
4869d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek
487a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
4889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4894f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Dir           = shift;
4904f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BaseDir       = shift;
4914f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $AnalyzerStats = shift;
49233e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose  my $KeepEmpty     = shift;
4939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
494fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
4959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
49723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
498363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
5009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
5019d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek  $baseDir = $Dir . "/";
5029d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek  find({ wanted => \&FileWanted, follow => 0}, $Dir);
5039d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek
5049d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek  if (scalar(@filesFound) == 0 and ! -e "$Dir/failures") {
50533e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    if (! $KeepEmpty) {
50633e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose      Diag("Removing directory '$Dir' because it contains no reports.\n");
50733e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose      system ("rm", "-fR", $Dir);
50833e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    }
509e09b8c41d0eeb17f8cbe73affb213cb7ff8d0718Jordan Rose    Diag("No bugs found.\n");
510363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
5119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
5125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
513991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  # Scan each report file and build an index.  
5144f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Index;
5154f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Stats;
5169d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek  foreach my $file (@filesFound) { ScanFile(\@Index, $Dir, $file, \@Stats); }
5175744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
518938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  # Scan the failures directory and use the information in the .info files
519d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # to update the common prefix directory.
520938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @failures;
521938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @attributes_ignored;
522938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (-d "$Dir/failures") {
523938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");
524938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
525d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    closedir(DIR);
526938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");        
527938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
528938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    closedir(DIR);
529938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    foreach my $file (@failures) {
530938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
531d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      my $Path = <IN>;
532d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      if (defined $Path) { UpdatePrefix($Path); }
533d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      close IN;
534d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    }    
535d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  }
536d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  
53763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
53863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
53963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
5405744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
5416e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
5426e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
5435744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
5445744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
5455744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
5467cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<title>${HtmlTitle}</title>
547f143545ce5ce125e7c1aa6fca9df372bfb604e9cTed Kremenek<link type="text/css" rel="stylesheet" href="scanview.css"/>
54822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
5496e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
5506e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
5516e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
5526e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
5536e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
5546e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
5556e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
5566e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
5576e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5586e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
559ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
5602350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenekfunction CopyCheckedStateToCheckButtons(SummaryCheckButton) {
5612350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  var Inputs = document.getElementsByTagName("input");
5622350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  for ( var i = 0 ; i < Inputs.length; ++i ) {
5632350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    if (Inputs[i].type == "checkbox") {
5642350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      if(Inputs[i] != SummaryCheckButton) {
5652350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].checked = SummaryCheckButton.checked;
5662350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].onclick();
5672350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek	  }
5682350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    }
5692350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  }
5702350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek}
5712350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek
572999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekfunction returnObjById( id ) {
573999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (document.getElementById) 
574999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.getElementById(id);
575999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.all)
576999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.all[id];
577999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.layers) 
578999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.layers[id];
579999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    return returnVar; 
580999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek}
581999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
582999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekvar NumUnchecked = 0;
583999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
5846e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
5856e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
5866e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
587999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (--NumUnchecked == 0) {
588999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek      returnObjById("AllBugsCheck").checked = true;
589999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    }
5906e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5916e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
5926e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
593999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    NumUnchecked++;
594999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    returnObjById("AllBugsCheck").checked = false;
5956e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5966e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
5976e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
5981d1abb1dec3d0b7609809d876a16a64a021e96e7Ted Kremenek<!-- SUMMARYENDHEAD -->
5996e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
6006e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
6017cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h1>${HtmlTitle}</h1>
6027cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6037cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<table>
6047cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
6057cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
6067cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
607b4882d50923881d1a01af4d5604b5baaa141cdf9Douglas Gregor<tr><th>Clang Version:</th><td>${ClangVersion}</td></tr>
6087cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Date:</th><td>${Date}</td></tr>
6097cba11262458df05951432b54997eb40a35dbf9eTed KremenekENDTEXT
6107cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6117cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
6127cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if (defined($BuildName) && defined($BuildDate));
6137cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6147cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT <<ENDTEXT;
6157cba11262458df05951432b54997eb40a35dbf9eTed Kremenek</table>
6166e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6176e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6189d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek  if (scalar(@filesFound)) {
619991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Print out the summary table.
620991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my %Totals;
621ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
622991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( @Index ) {
623ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_type = ($row->[2]);
624ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_category = ($row->[1]);
625ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $key = "$bug_category:$bug_type";
626ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
627ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
628ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else { $Totals{$key}->[0]++; }
6296e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
630991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6317cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    print OUT "<h2>Bug Summary</h2>";
632991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
633991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $BuildName) {
634991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
6356e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
636f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
6372350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  my $TotalBugs = scalar(@Index);
6386e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
639ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table>
640ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
641999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed 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>
6426e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6436e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
644ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    my $last_category;
645ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
646ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $key (
647ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      sort {
648ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $x = $Totals{$a};
649ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $y = $Totals{$b};
650ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $res = $x->[1] cmp $y->[1];
651ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res = $x->[2] cmp $y->[2] if ($res == 0);
652ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res
653ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      } keys %Totals ) 
654ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    {
655ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $val = $Totals{$key};
656ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $category = $val->[1];
657ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $last_category or $last_category ne $category) {
658ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $last_category = $category;
659ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
660ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }      
661ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = lc $key;
662ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
663ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr><td class=\"SUMM_DESC\">";
664ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[2];
6652350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      print OUT "</td><td class=\"Q\">";
666ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[0];
667ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
668991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
6696e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6706e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
6716e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
6736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
6747cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h2>Reports</h2>
675ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
676ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table class="sortable" style="table-layout:automatic">
677ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr>
678ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td>Bug Group</td>
679ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
680bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
681ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="Q">Line</td>
68281983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek  <td class="Q">Path Length</td>
6832645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
684ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <!-- REPORTBUGCOL -->
685ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek</tr></thead>
686ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<tbody>
6875744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
6889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
689991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $prefix = GetPrefix();
690991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $regex;
691991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFileRegex;
692991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFilePrefix = "File:</td><td>";
6937a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
694991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $prefix) { 
695991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $regex = qr/^\Q$prefix\E/is;    
696991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
697991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }    
6987a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
699ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
700ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = "$row->[1]:$row->[2]";
701ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x = lc $x;
702ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
7036e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
704991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $ReportFile = $row->[0];
705ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          
706ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr class=\"bt_$x\">";
707ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
708991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT $row->[1];
709ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
710ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
711ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $row->[2];
712ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
713ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
714ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Update the file prefix.      
715ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $fname = $row->[3];
716ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
717991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (defined $regex) {
718991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $fname =~ s/$regex//;
719991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
720991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
721ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
72291639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      print OUT "<td>";      
723ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my @fname = split /\//,$fname;
724ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if ($#fname > 0) {
725ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        while ($#fname >= 0) {
726ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          my $x = shift @fname;
727ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          print OUT $x;
728ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          if ($#fname >= 0) {
729ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek            print OUT "<span class=\"W\"> </span>/";
730ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          }
731ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        }
732ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
733ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else {
734ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT $fname;
73591639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      }      
736ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
737ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
738ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Print out the quantities.
73981983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for my $j ( 4 .. 5 ) {
740ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td class=\"Q\">$row->[$j]</td>";        
741ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
742ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
743991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Print the rest of the columns.
74481983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for (my $j = 6; $j <= $#{$row}; ++$j) {
745ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td>$row->[$j]</td>"
746991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
7477f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
748991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Emit the "View" link.
74968005ddb49b88c2f6cdd88185d72d8b411d2dbc9Ted Kremenek      print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
7503cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
751e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar      # Emit REPORTBUG markers.
752ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
753e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar        
754991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # End the row.
755991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</tr>\n";
756991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
757991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
758ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    print OUT "</tbody>\n</table>\n\n";
759991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  }
760991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
761938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar (@failures) || scalar(@attributes_ignored)) {
762938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    print OUT "<h2>Analyzer Failures</h2>\n";
763938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
764938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @attributes_ignored) {
765938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "The analyzer's parser ignored the following attributes:<p>\n";
766938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
767938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
768938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @attributes_ignored) {
769938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
770938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $attribute = $1;
771938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the attribute file to get the first file that failed.
772938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (!open (ATTR, "$Dir/failures/$file"));
773938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile = <ATTR>;
774938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $ppfile;
775938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close ATTR;
776938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (! -e "$Dir/failures/$ppfile");
777938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the info file and get the name of the source file.
778938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$ppfile.info.txt") or
779938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$ppfile.info.txt\n";
780938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $srcfile = <INFO>;
781938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $srcfile;
782938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close (INFO);
783938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Print the information in the table.
784938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $prefix = GetPrefix();
785938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
786938eef139ad43345248235da31f78a759dd18f13Ted 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";
787938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile_clang = $ppfile;
788938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
789938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
790938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      }
791938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
792938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }
793938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
794938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @failures) {
795938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<p>The analyzer had problems processing the following files:</p>\n";
796938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
797938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
798938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @failures) {
79982a1253077cd0832e4d347062b911cd305ab62d1Ted Kremenek        $file =~ /(.+).info.txt$/;
800991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Get the preprocessed file.
801991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $ppfile = $1;
802991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Open the info file and get the name of the source file.
803938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$file") or
804938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$file\n";
805991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $srcfile = <INFO>;
8065d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $srcfile;
8075d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        my $problem = <INFO>;
8085d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $problem;
809991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        close (INFO);
810991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Print the information in the table.
811d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        my $prefix = GetPrefix();
8129f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
813938eef139ad43345248235da31f78a759dd18f13Ted 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";
814ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        my $ppfile_clang = $ppfile;
815ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
816938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
817991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
818938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
819938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }    
820e2c8663ad2b110712401145b866072bb94108058Nico 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";
8215744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
8225744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
823991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  print OUT "</body></html>\n";  
8245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
8253ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  CopyFiles($Dir);
82620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
82720161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
82820161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
829fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
83020161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
8314f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Print statistics
8324f2b10b24bab0049020d268382eda144e2aa064cTom Care  print CalcStats(\@Stats) if $AnalyzerStats;
8334f2b10b24bab0049020d268382eda144e2aa064cTom Care
83423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
835150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
836150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
8375950b3f93a6e8a6ae8bd59a0ef5797e9f88f0bc3Ted Kremenek    Diag("Run 'scan-view $Dir' to examine bug reports.\n");
838150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
839363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
840938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
841991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
842363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
8439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
846dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
847dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
848dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
8496b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
8506b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
8516b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
8526b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
8536b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8546b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
8556b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
8566b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
8576b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
8586b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
8596b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8606b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8616b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
8626b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
8636b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8646b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
8656b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
866cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremeneksub SetEnv {
867cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift @_;
868cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  foreach my $opt ('CC', 'CXX', 'CLANG', 'CLANG_CXX',
869cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS') {
870cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    die "$opt is undefined\n" if (!defined $opt);
871cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{$opt} = $Options->{$opt};
872cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
873cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  foreach my $opt ('CCC_ANALYZER_STORE_MODEL',
874cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_PLUGINS',
875cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_INTERNAL_STATS',
876cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_OUTPUT_FORMAT') {
877cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    my $x = $Options->{$opt};
878cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    if (defined $x) { $ENV{$opt} = $x }
879cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
880cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Verbose = $Options->{'VERBOSE'};
881cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  if ($Verbose >= 2) {
882cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
883cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
884cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  if ($Verbose >= 3) {
885cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{'CCC_ANALYZER_LOG'} = 1;
886cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
887cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek}
888cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
88938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremeneksub RunXcodebuild {
89038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $Args = shift;
89138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $IgnoreErrors = shift;
89238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $CCAnalyzer = shift;
89338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $CXXAnalyzer = shift;
894cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift;
895cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
89638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if ($IgnoreErrors) {
89738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
89838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
8991afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek
9001afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  # Detect the version of Xcode.  If Xcode 4.6 or higher, use new
9011afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  # in situ support for analyzer interposition without needed to override
9021afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  # the compiler.
9031afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  open(DETECT_XCODE, "xcodebuild -version |") or
9041afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    die "error: cannot detect version of xcodebuild\n";
9051afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek
9061afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  my $oldBehavior = 1;
9071afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek
9081afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  while(<DETECT_XCODE>) {
9091afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    if (/^Xcode (.+)$/) {
910c73dcba91872322159b94dc49afb9c86d169425eTed Kremenek      my $ver = $1;
911c73dcba91872322159b94dc49afb9c86d169425eTed Kremenek      if ($ver =~ /^([0-9]+[.][0-9]+)[^0-9]?/) {
912c73dcba91872322159b94dc49afb9c86d169425eTed Kremenek        if ($1 >= 4.6) {
913c73dcba91872322159b94dc49afb9c86d169425eTed Kremenek          $oldBehavior = 0;
914c73dcba91872322159b94dc49afb9c86d169425eTed Kremenek          last;
915c73dcba91872322159b94dc49afb9c86d169425eTed Kremenek        }
9161afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek      }
9171afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    }
9181afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  }
9191afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  close(DETECT_XCODE);
9201afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  
9211afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  if ($oldBehavior == 0) {
9221afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    my $OutputDir = $Options->{"OUTPUT_DIR"};
9231afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    my $CLANG = $Options->{"CLANG"};
9241afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    push @$Args,
9251afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek        "RUN_CLANG_STATIC_ANALYZER=YES",
9261afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek        "CLANG_ANALYZER_OUTPUT=plist-html",
9271afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek        "CLANG_ANALYZER_EXEC=$CLANG",
9281afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek        "CLANG_ANALYZER_OUTPUT_DIR=$OutputDir";
9291afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek
9301afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek    return (system(@$Args) >> 8);
9311afc201e644ce6379b115b1fae0608dee1b0ab5fTed Kremenek  }
93238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
933cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  # Default to old behavior where we insert a bogus compiler.
934cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  SetEnv($Options);
935cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  
93638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # Check if using iPhone SDK 3.0 (simulator).  If so the compiler being
93738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # used should be gcc-4.2.
93838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if (!defined $ENV{"CCC_CC"}) {
93938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
94038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek      if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
94138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek        if (@$Args[$i+1] =~ /^iphonesimulator3/) {
94238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek          $ENV{"CCC_CC"} = "gcc-4.2";
943cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek          $ENV{"CCC_CXX"} = "g++-4.2";
94438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek        }
94538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek      }
94638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    }
94738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
94838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek
94938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # Disable PCH files until clang supports them.
95038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
95138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
95238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
95338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
95438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # (via c++-analyzer) when linking such files.
95538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
95638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek 
95738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  return (system(@$Args) >> 8); 
95838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek}
95938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek
960cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremeneksub RunBuildCommand {  
961dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
9627442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
963dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
9646195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
965524c308506e77e173092e87a0724a27817311428Ted Kremenek  my $CXXAnalyzer = shift;
966cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift;
967dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
9683301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
9693301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
9703301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
9713301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
9723301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
97338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if ($Cmd eq "xcodebuild") {
974cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options);
97538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
97638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
977cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  # Setup the environment.
978cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  SetEnv($Options);
979cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  
98092548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek  if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or 
98192548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?cc[^\/]*$)/ or
98292548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
98305acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek      $Cmd =~ /(.*\/?clang$)/ or 
98492548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
98592548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek
98692548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
98751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CC"} = $1;      
98892548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    }
98992548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek        
990dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
9916195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
992dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
99351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  elsif ($Cmd =~ /(.*\/?g\+\+[^\/]*$)/ or 
99451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+[^\/]*$)/ or
99551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?llvm-g\+\+[^\/]*$)/ or
99605acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek        $Cmd =~ /(.*\/?clang\+\+$)/ or
99751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+-analyzer[^\/]*$)/) {
99851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    if (!($Cmd =~ /c\+\+-analyzer/) and !defined $ENV{"CCC_CXX"}) {
99951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CXX"} = $1;      
100051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    }        
100151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    shift @$Args;
1002524c308506e77e173092e87a0724a27817311428Ted Kremenek    unshift @$Args, $CXXAnalyzer;
100351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  }
10047442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
10057442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
10066fba85dc6509069ff7735283464bd02da2da6eebTed Kremenek      AddIfNotPresent($Args, "CC=$CCAnalyzer");
1007524c308506e77e173092e87a0724a27817311428Ted Kremenek      AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
10086b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
10098912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
10107442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
10116b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
101287752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek
10135a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
1014dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
1015dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
1016dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
10179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
10189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
10199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1020a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
10219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
10225744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
1023a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
10242b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1025f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
1026f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
1027fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
1028f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
1029f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
1030f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
1031f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
10322b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
10332b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1034eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -analyze-headers
10358382cf57b722f130f1a6b45380639871c07271c1Ted Kremenek 
1036eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Also analyze functions in #included files.  By default, such functions
1037eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   are skipped unless they are called by functions within the main source file.
1038eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1039eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -o <output location>
1040eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1041eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specifies the output directory for analyzer reports. Subdirectories will be
1042eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   created as needed to represent separate "runs" of the analyzer. If this
1043eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   option is not specified, a directory is created in /tmp (TMPDIR on Mac OS X)
1044eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   to store the reports.
1045eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1046eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -h             
1047363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
10481262fc4d66584224234691d30d779f8ff004585cTed Kremenek
1049eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Display this message.
1050eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1051eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -k
1052eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --keep-going
1053eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek				  
1054eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Add a "keep on going" option to the specified build command. This option
1055eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   currently supports make and xcodebuild. This is a convenience option; one
1056eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   can specify this behavior directly using build options.
1057eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1058eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --html-title [title]
1059eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --html-title=[title]
10602b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1061eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specify the title used on generated HTML pages. If not specified, a default
1062eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   title will be used.
10637cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1064eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -plist
10652c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
1066eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default the output of scan-build is a set of HTML files. This option
1067eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   outputs the results as a set of .plist files.
10682c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
1069eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -plist-html
1070eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1071eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default the output of scan-build is a set of HTML files. This option
1072eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   outputs the results as a set of HTML and .plist files.
1073eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1074eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --status-bugs
1075eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1076eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default, the exit status of scan-build is the same as the executed build
1077eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   command. Specifying this option causes the exit status of scan-build to be 1
1078eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   if it found potential bugs and 0 otherwise.
1079386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
1080eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-cc [compiler path]   
1081eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-cc=[compiler path]
1082eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1083eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   scan-build analyzes a project by interposing a "fake compiler", which
1084eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   executes a real compiler for compilation and the static analyzer for analysis.
1085eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Because of the current implementation of interposition, scan-build does not
1086eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   know what compiler your project normally uses.  Instead, it simply overrides
1087eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   the CC environment variable, and guesses your default compiler.
1088eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   
1089eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   In the future, this interposition mechanism to be improved, but if you need
1090eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   scan-build to use a specific compiler for *compilation* then you can use
1091eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   this option to specify a path to that compiler.
1092eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1093eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-c++ [compiler path]
1094eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-c++=[compiler path]
1095eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1096eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   This is the same as "-use-cc" but for C++ code.
1097eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1098eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -v
1099eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1100eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Enable verbose output from scan-build. A second and third '-v' increases
1101eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   verbosity.
1102f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
1103eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -V
1104eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --view
1105363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
1106eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   View analysis results in a web browser when the build completes.
11077f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
1108be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed KremenekADVANCED OPTIONS:
1109be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
1110eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -no-failure-reports
1111eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1112eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Do not create a 'failures' subdirectory that includes analyzer crash reports
1113eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   and preprocessed source files.
1114b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1115eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -stats
1116eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1117eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Generates visitation statistics for the project being analyzed.
11184f2b10b24bab0049020d268382eda144e2aa064cTom Care
1119eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -maxloop <loop count>
11201e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks 
1121eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specifiy the number of times a block can be visited before giving up.
1122eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Default is 4. Increase for more comprehensive coverage at a cost of speed.
1123eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1124eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -internal-stats
1125eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1126eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Generate internal analyzer statistics.
1127810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 
11285a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek --use-analyzer [Xcode|path to clang] 
11295a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek --use-analyzer=[Xcode|path to clang]
1130810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 
1131810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   scan-build uses the 'clang' executable relative to itself for static
1132810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   analysis. One can override this behavior with this option by using the
1133810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   'clang' packaged with Xcode (on OS X) or from the PATH.
113433e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose
113533e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose --keep-empty
113633e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose
113733e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose   Don't remove the build results directory even if no issues were reported.
113833e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose
113909fbf297da918760ce33302a3f709a77f43af265Ted KremenekCONTROLLING CHECKERS:
114009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
114109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek A default group of checkers are always run unless explicitly disabled.
114209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek Checkers may be enabled/disabled using the following options:
114309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
114409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -enable-checker [checker name]
114509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -disable-checker [checker name]
1146f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks 
1147f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna ZaksLOADING CHECKERS:
1148f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1149f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks Loading external checkers using the clang plugin interface:
1150f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1151f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks -load-plugin [plugin library]
1152d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
1153b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1154ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for list of checkers that are enabled.
1155f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1156f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# create a list to load the plugins via the 'Xclang' command line
1157f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# argument
1158f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginLoadCommandline_xclang;
1159f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksforeach my $param ( @PluginsToLoad ) {
1160f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, "-Xclang" );
1161f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, $param );
1162f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks}
1163ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy %EnabledCheckers;
1164ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekforeach my $lang ("c", "objective-c", "objective-c++", "c++") {
1165ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  pipe(FROM_CHILD, TO_PARENT);
1166ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $pid = fork();
1167ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if ($pid == 0) {
1168ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    close FROM_CHILD;
1169ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDOUT,">&", \*TO_PARENT);
1170ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDERR,">&", \*TO_PARENT);
1171f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###'); 
1172ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1173ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(TO_PARENT);
1174ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1175ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    foreach my $val (split /\s+/) {
1176ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $val =~ s/\"//g;
1177ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($val =~ /-analyzer-checker\=([^\s]+)/) {
1178ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $EnabledCheckers{$1} = 1;
1179ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1180ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1181ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1182ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  waitpid($pid,0);
1183ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(FROM_CHILD);
1184ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1185ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1186ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for complete list of checkers.
1187a778d710e2c62d62e0b78d120254764142801196Jordan Roseif (defined $Clang && -x $Clang) {
1188a778d710e2c62d62e0b78d120254764142801196Jordan Rose  pipe(FROM_CHILD, TO_PARENT);
1189a778d710e2c62d62e0b78d120254764142801196Jordan Rose  my $pid = fork();
1190a778d710e2c62d62e0b78d120254764142801196Jordan Rose  if ($pid == 0) {
1191a778d710e2c62d62e0b78d120254764142801196Jordan Rose    close FROM_CHILD;
1192a778d710e2c62d62e0b78d120254764142801196Jordan Rose    open(STDOUT,">&", \*TO_PARENT);
1193a778d710e2c62d62e0b78d120254764142801196Jordan Rose    open(STDERR,">&", \*TO_PARENT);
1194a778d710e2c62d62e0b78d120254764142801196Jordan Rose    exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
1195ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1196a778d710e2c62d62e0b78d120254764142801196Jordan Rose  close(TO_PARENT);
1197a778d710e2c62d62e0b78d120254764142801196Jordan Rose  my $foundCheckers = 0;
1198ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1199a778d710e2c62d62e0b78d120254764142801196Jordan Rose    if (/CHECKERS:/) {
1200a778d710e2c62d62e0b78d120254764142801196Jordan Rose      $foundCheckers = 1;
1201a778d710e2c62d62e0b78d120254764142801196Jordan Rose      last;
120273078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek    }
1203a778d710e2c62d62e0b78d120254764142801196Jordan Rose  }
1204a778d710e2c62d62e0b78d120254764142801196Jordan Rose  if (!$foundCheckers) {
1205a778d710e2c62d62e0b78d120254764142801196Jordan Rose    print "  *** Could not query Clang for the list of available checkers.";
1206a778d710e2c62d62e0b78d120254764142801196Jordan Rose  }
1207a778d710e2c62d62e0b78d120254764142801196Jordan Rose  else {
1208a778d710e2c62d62e0b78d120254764142801196Jordan Rose    print("\nAVAILABLE CHECKERS:\n\n");
1209a778d710e2c62d62e0b78d120254764142801196Jordan Rose    my $skip = 0;
1210a778d710e2c62d62e0b78d120254764142801196Jordan Rose    while(<FROM_CHILD>) {
1211a778d710e2c62d62e0b78d120254764142801196Jordan Rose      if (/experimental/) {
1212a778d710e2c62d62e0b78d120254764142801196Jordan Rose        $skip = 1;
1213a778d710e2c62d62e0b78d120254764142801196Jordan Rose        next;
1214a778d710e2c62d62e0b78d120254764142801196Jordan Rose      }
1215a778d710e2c62d62e0b78d120254764142801196Jordan Rose      if ($skip) {
1216a778d710e2c62d62e0b78d120254764142801196Jordan Rose        next if (!/^\s\s[^\s]/);
1217a778d710e2c62d62e0b78d120254764142801196Jordan Rose        $skip = 0;
1218ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1219a778d710e2c62d62e0b78d120254764142801196Jordan Rose      s/^\s\s//;
1220a778d710e2c62d62e0b78d120254764142801196Jordan Rose      if (/^([^\s]+)/) {
1221a778d710e2c62d62e0b78d120254764142801196Jordan Rose        # Is the checker enabled?
1222a778d710e2c62d62e0b78d120254764142801196Jordan Rose        my $checker = $1;
1223a778d710e2c62d62e0b78d120254764142801196Jordan Rose        my $enabled = 0;
1224a778d710e2c62d62e0b78d120254764142801196Jordan Rose        my $aggregate = "";
1225a778d710e2c62d62e0b78d120254764142801196Jordan Rose        foreach my $domain (split /\./, $checker) {
1226a778d710e2c62d62e0b78d120254764142801196Jordan Rose          $aggregate .= $domain;
1227a778d710e2c62d62e0b78d120254764142801196Jordan Rose          if ($EnabledCheckers{$aggregate}) {
1228a778d710e2c62d62e0b78d120254764142801196Jordan Rose            $enabled =1;
1229a778d710e2c62d62e0b78d120254764142801196Jordan Rose            last;
1230a778d710e2c62d62e0b78d120254764142801196Jordan Rose          }
1231a778d710e2c62d62e0b78d120254764142801196Jordan Rose          # append a dot, if an additional domain is added in the next iteration
1232a778d710e2c62d62e0b78d120254764142801196Jordan Rose          $aggregate .= ".";
1233a778d710e2c62d62e0b78d120254764142801196Jordan Rose        }
1234ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      
1235a778d710e2c62d62e0b78d120254764142801196Jordan Rose        if ($enabled) {
1236a778d710e2c62d62e0b78d120254764142801196Jordan Rose          print " + ";
1237a778d710e2c62d62e0b78d120254764142801196Jordan Rose        }
1238a778d710e2c62d62e0b78d120254764142801196Jordan Rose        else {
1239a778d710e2c62d62e0b78d120254764142801196Jordan Rose          print "   ";
1240a778d710e2c62d62e0b78d120254764142801196Jordan Rose        }
1241ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1242ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      else {
1243ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print "   ";
1244ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1245a778d710e2c62d62e0b78d120254764142801196Jordan Rose      print $_;
1246ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1247a778d710e2c62d62e0b78d120254764142801196Jordan Rose    print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
1248a778d710e2c62d62e0b78d120254764142801196Jordan Rose  }
1249a778d710e2c62d62e0b78d120254764142801196Jordan Rose  waitpid($pid,0);
1250a778d710e2c62d62e0b78d120254764142801196Jordan Rose  close(FROM_CHILD);
1251ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
12527fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1253b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
1254b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
12552b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
12562b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1257363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
125839eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
12595744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
12602b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1261eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek scan-build -o /tmp/myhtmldir make -j4
12622b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
1263eaafdfc7b475937ed194ad729407481054b99be9Ted KremenekThe above example causes analysis reports to be deposited into a subdirectory
1264eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenekof "/tmp/myhtmldir" and to run "make" with the "-j4" option. A different
1265eaafdfc7b475937ed194ad729407481054b99be9Ted Kremeneksubdirectory is created each time scan-build analyzes a project. The analyzer
1266eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenekshould support most parallel builds, but not distributed builds.
12672b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
12682b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
12699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
12709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
12727cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# HtmlEscape - HTML entity encode characters that are special in HTML
12737cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12747cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12757cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub HtmlEscape {
12767cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
12777cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
12787cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $tmp = $arg;
127987f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/&/&amp;/g;
128087f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/</&lt;/g;
128187f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/>/&gt;/g;
12827cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  return $tmp;
12837cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
12847cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12857cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12867cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# ShellEscape - backslash escape characters that are special to the shell
12877cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12887cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12897cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub ShellEscape {
12907cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
12917cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
129287f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
129387f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  return $arg;
12947cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
12957cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12967cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
12989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
12999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1300e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekmy $AnalyzeHeaders = 0;
13019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
13029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
13037f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
1304363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
130533e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rosemy $KeepEmpty    = 0;  # Don't remove output directory even with 0 results.
1306b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
130707c3767be59472e19183c7b51fae76481465cb51Zhongxing Xumy $StoreModel;
1308be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekmy $ConstraintsModel;
13091e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaksmy $InternalStats;
13108d8bc9157fccab6a4089c41cdad9e12045edd736Ted Kremenekmy $OutputFormat = "html";
13114f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $AnalyzerStats = 0;
13124f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $MaxLoop = 0;
13139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
13149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
13159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1316a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
13179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
13189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1319ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1320ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $displayHelp = 0;
1321810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $AnalyzerDiscoveryMethod;
1322ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
13239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
13249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
13269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
13289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
13292f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
1330ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $displayHelp = 1;
1331ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    shift @ARGV;
1332ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    next;
13339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1335e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  if ($arg eq '-analyze-headers') {
1336e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    shift @ARGV;    
1337e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    $AnalyzeHeaders = 1;
1338e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    next;
1339e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  }
1340e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
13419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
13429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
13449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
134523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
13469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
13479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1348db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # Construct an absolute path.  Uses the current working directory
1349db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # as a base if the original path was not absolute.
1350db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    $HtmlDir = abs_path(shift @ARGV);
1351db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    
13529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13547cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13557cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--html-title(=(.+))?$/) {
13567cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    shift @ARGV;
13577cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1358278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq '') {
13597cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      if (!@ARGV) {
13607cba11262458df05951432b54997eb40a35dbf9eTed Kremenek        DieDiag("'--html-title' option requires a string.\n");
13617cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      }
13627cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13637cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = shift @ARGV;
13647cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    } else {
13657cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = $2;
13667cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    }
13677cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13687cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    next;
13697cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  }
13709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13712b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
13729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
13749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13767fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1377f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
1378f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
1379f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
1380f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1381278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1382f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
1383f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
1384f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
1385f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
1386f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1387f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
1388f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
1389f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1390f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1391f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
1392f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
1393f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
1394f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
13957cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
1396386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
139751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    my $cxx;    
1398386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
1399278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1400386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
1401386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
1402386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
140351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = shift @ARGV;
1404386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
1405386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
140651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = $2;
1407386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
140851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    
140951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    $ENV{"CCC_CXX"} = $cxx;
1410386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
1411386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
1412386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
14139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
14149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
14159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
14169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
14179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
14189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
14197f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
14207f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
14217f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
14227f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
14237f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
14247f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
1425363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
1426363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
1427363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
1428363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
1429363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
143007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu
143107c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  if ($arg eq "-store") {
143207c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    shift @ARGV;
1433be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $StoreModel = shift @ARGV;
1434be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    next;
1435be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  }
1436be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  
1437be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  if ($arg eq "-constraints") {
1438be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    shift @ARGV;
1439be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $ConstraintsModel = shift @ARGV;
144007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    next;
144107c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  }
14421e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks
14431e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks  if ($arg eq "-internal-stats") {
14441e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    shift @ARGV;
14451e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    $InternalStats = 1;
14461e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    next;
14471e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks  }
1448363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
1449db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  if ($arg eq "-plist") {
1450db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    shift @ARGV;
1451db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    $OutputFormat = "plist";
1452db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    next;
1453db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
14547753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  if ($arg eq "-plist-html") {
14557753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    shift @ARGV;
14567753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    $OutputFormat = "plist-html";
14577753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    next;
14587753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  }
1459e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  
1460e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  if ($arg eq "-no-failure-reports") {
1461e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    $ENV{"CCC_REPORT_FAILURES"} = 0;
1462e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    next;
1463e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  }
14644f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-stats") {
14654f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
14664f2b10b24bab0049020d268382eda144e2aa064cTom Care    $AnalyzerStats = 1;
14674f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
14684f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
14694f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-maxloop") {
14704f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
14714f2b10b24bab0049020d268382eda144e2aa064cTom Care    $MaxLoop = shift @ARGV;
14724f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
14734f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
147409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-enable-checker") {
147509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
147609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-checker", shift @ARGV;
147709fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
147809fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
147909fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-disable-checker") {
148009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
148109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV;
148209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
148309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
1484f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  if ($arg eq "-load-plugin") {
1485f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    shift @ARGV;
1486f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    push @PluginsToLoad, "-load", shift @ARGV;
1487f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    next;
1488f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  }
14895a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek  if ($arg eq "--use-analyzer") {
1490810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 	shift @ARGV;
1491810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  	$AnalyzerDiscoveryMethod = shift @ARGV;
1492810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	next;
1493810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
14945a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek  if ($arg =~ /^--use-analyzer=(.+)$/) {
1495810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    shift @ARGV;
1496810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	$AnalyzerDiscoveryMethod = $1;
1497810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	next;
1498810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
149933e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose  if ($arg eq "--keep-empty") {
150033e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    shift @ARGV;
150133e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    $KeepEmpty = 1;
150233e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    next;
150333e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose  }
1504f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  
150523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
15060062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
15079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
15089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
15099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1510ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!@ARGV and $displayHelp == 0) {
151123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
1512ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  $displayHelp = 1;
1513ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1514ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1515810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek# Find 'clang'
1516810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekif (!defined $AnalyzerDiscoveryMethod) {
1517810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  $Clang = Cwd::realpath("$RealBin/bin/clang");
1518810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  if (!defined $Clang || ! -x $Clang) {
1519810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = Cwd::realpath("$RealBin/clang");
1520810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1521810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  if (!defined $Clang || ! -x $Clang) {
1522a778d710e2c62d62e0b78d120254764142801196Jordan Rose    if (!$displayHelp) {
1523a778d710e2c62d62e0b78d120254764142801196Jordan Rose      DieDiag("error: Cannot find an executable 'clang' relative to scan-build." .
1524a778d710e2c62d62e0b78d120254764142801196Jordan Rose   	          "  Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n");
1525a778d710e2c62d62e0b78d120254764142801196Jordan Rose    }
1526810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1527810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek} 
1528810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekelse {  
15290d3a3fd7211a1b368d1f8c0d7ca1cfd40d31a0eaTed Kremenek  if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) {
1530810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	my $xcrun = `which xcrun`;
1531810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    chomp $xcrun;
1532810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	if ($xcrun eq "") {
1533810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  	  DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n");
1534810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	}
1535810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = `$xcrun -toolchain XcodeDefault -find clang`;
1536810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    chomp $Clang;  
1537810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    if ($Clang eq "") {
1538810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek      DieDiag("No 'clang' executable found by 'xcrun'\n"); 
1539810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    }
1540810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1541810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  else {
1542810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = Cwd::realpath($AnalyzerDiscoveryMethod);
15439d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek	if (!defined $Clang or not -x $Clang) {
15449d9f254f7781c157256dbde4d4d961a2d89e8599Ted Kremenek   	  DieDiag("Cannot find an executable clang at '$AnalyzerDiscoveryMethod'\n");
1545810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	}
1546810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1547810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek}
1548810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek
1549a778d710e2c62d62e0b78d120254764142801196Jordan Roseif ($displayHelp) {
1550a778d710e2c62d62e0b78d120254764142801196Jordan Rose  DisplayHelp();
1551a778d710e2c62d62e0b78d120254764142801196Jordan Rose  exit 1;
1552a778d710e2c62d62e0b78d120254764142801196Jordan Rose}
1553a778d710e2c62d62e0b78d120254764142801196Jordan Rose
1554810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX = $Clang;
1555810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX =~ s/\-\d+\.\d+$//;
1556810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX .= "++";
155747135fe346b101c9bfb15c7309423fb57ec533f0Ted Kremenek# Make sure to use "" to handle paths with spaces.
155847135fe346b101c9bfb15c7309423fb57ec533f0Ted Kremenek$ClangVersion = HtmlEscape(`"$Clang" --version`);
1559810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek
1560ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine where results go.
15617cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
15627cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
15637cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  unless (defined($HtmlTitle));
1564386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
15659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
1566684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
1567a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
15689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1569ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine the location of ccc-analyzer.
157051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $AbsRealBin = Cwd::realpath($RealBin);
157151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $Cmd = "$AbsRealBin/libexec/ccc-analyzer";
157251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $CmdCXX = "$AbsRealBin/libexec/c++-analyzer";
157351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek
1574ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenekif (!defined $Cmd || ! -x $Cmd) {
157551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $Cmd = "$AbsRealBin/ccc-analyzer";
15766b89636db873142f562cf576df9bc195c5b8674bTed Kremenek  DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
1577ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenek}
157851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekif (!defined $CmdCXX || ! -x $CmdCXX) {
157951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $CmdCXX = "$AbsRealBin/c++-analyzer";
158051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
158151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek}
1582f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
1583810e6229e59796f8109e94e4a469a2dc17cf3e6dTed KremenekDiag("Using '$Clang' for static analysis\n");
15840b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
1585ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted KremenekSetHtmlEnv(\@ARGV, $HtmlDir);
1586cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekif ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; }
1587cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekif ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; }
1588be92debbf1e9c38b1ae8a4a9c30377b24196ca73Ted Kremenekif ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; }
1589cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
1590cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek# Delay setting up other environment variables in case we can do true
1591cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek# interposition.
1592cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $CCC_ANALYZER_ANALYSIS = join ' ',@AnalysesToRun;
1593cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $CCC_ANALYZER_PLUGINS = join ' ',@PluginsToLoad;
1594cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy %Options = (
1595cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CC' => $Cmd,
1596cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CXX' => $CmdCXX,
1597cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CLANG' => $Clang,
1598cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CLANG_CXX' => $ClangCXX,
1599cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'VERBOSE' => $Verbose,
1600cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CCC_ANALYZER_ANALYSIS' => $CCC_ANALYZER_ANALYSIS,
1601cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CCC_ANALYZER_PLUGINS' => $CCC_ANALYZER_PLUGINS,
1602cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'OUTPUT_DIR' => $HtmlDir
1603cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek);
1604f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
16053cab2b1c3798f2a6aa3526875801a02aebf6fc1dZhongxing Xuif (defined $StoreModel) {
1606cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
160707c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu}
1608be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekif (defined $ConstraintsModel) {
1609cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
1610be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek}
16111e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaksif (defined $InternalStats) {
1612cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_INTERNAL_STATS'} = 1;
16131e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks}
1614db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenekif (defined $OutputFormat) {
1615cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
1616db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek}
1617db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
16189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
1619cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX,
1620cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                                \%Options);
16219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
16227753b352366778d01c5cda4117356f181d3dd468Ted Kremenekif (defined $OutputFormat) {
16231182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  if ($OutputFormat =~ /plist/) {
16241182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis run complete.\n";
16251182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
16261182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  }
16277a334d9ed9ff7426e78a88582207b47b370ec5deTed Kremenek  if ($OutputFormat =~ /html/) {
16287753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    # Postprocess the HTML directory.
162933e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats, $KeepEmpty);
16307753b352366778d01c5cda4117356f181d3dd468Ted Kremenek
16317753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ViewResults and -r "$HtmlDir/index.html") {
16327753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Analysis run complete.\n";
16337753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
16347753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      my $ScanView = Cwd::realpath("$RealBin/scan-view");
16357753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      if (! -x $ScanView) { $ScanView = "scan-view"; }
16367753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exec $ScanView, "$HtmlDir";
16377753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1638db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
16397753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ExitStatusFoundBugs) {
16407753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 1 if ($NumBugs > 0);
16417753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 0;
16427753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1643db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
1644363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
1645363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
16465656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
16475656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
1648