19cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#!/usr/bin/env perl
29cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
39cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#                     The LLVM Compiler Infrastructure
49cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
59cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# This file is distributed under the University of Illinois Open Source
69cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# License. See LICENSE.TXT for details.
79cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
89cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##===----------------------------------------------------------------------===##
99cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# A script designed to wrap a build so that all calls to gcc are intercepted
119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# and piped to the static analyzer.
129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##===----------------------------------------------------------------------===##
149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse strict;
169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse warnings;
1722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenekuse FindBin qw($RealBin);
18a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenekuse Digest::MD5;
197a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekuse File::Basename;
2023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor;
2123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor qw(:constants);
22cd25c13ade3afa829c87ca1ed0ed0d379f426251Ted Kremenekuse Cwd qw/ getcwd abs_path /;
237cba11262458df05951432b54997eb40a35dbf9eTed Kremenekuse Sys::Hostname;
249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Verbose = 0;       # Verbose output from this script.
269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Prog = "scan-build";
27f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildName;
28f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildDate;
299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
300e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $TERM = $ENV{'TERM'};
31c9480dd03522f0bab5fff7d30402cb7ee31117dcTed Kremenekmy $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT
320e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenek                and defined $ENV{'SCAN_BUILD_COLOR'});
3323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
347cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $UserName = HtmlEscape(getpwuid($<) || 'unknown');
357cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HostName = HtmlEscape(hostname() || 'unknown');
367cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDir = HtmlEscape(getcwd());
377cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDirSuffix = basename($CurrentDir);
387cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
39f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginsToLoad;
407cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CmdArgs;
417cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
427cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HtmlTitle;
437cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
447cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $Date = localtime();
457cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
46b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
47b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Diagnostics
48b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
49b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
5023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
5123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
5223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
5323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
5423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
5823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
5923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
60991c54b9b7409656e5593364e065878b5210d556Ted Kremeneksub DiagCrashes {
61991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Dir = shift;
62938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("The analyzer encountered problems on some source files.\n");
63938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("Preprocessed versions of these sources were deposited in '$Dir/failures'.\n");
64991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("Please consider submitting a bug report using these files:\n");
65e2c8663ad2b110712401145b866072bb94108058Nico Weber  Diag ("  http://clang-analyzer.llvm.org/filing_bugs.html\n")
66991c54b9b7409656e5593364e065878b5210d556Ted Kremenek}
67991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
6923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
7023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
7123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
7223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
7323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
7523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
7623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
7823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
7923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
818db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek# Print default checker names
828db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek##----------------------------------------------------------------------------##
838db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek
848db26ce0464c712058ab60b72e2a70c04148020eTed Kremenekif (grep /^--help-checkers$/, @ARGV) {
858db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    my @options = qx($0 -h);
868db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    foreach (@options) {
878db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	next unless /^ \+/;
888db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	s/^\s*//;
898db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	my ($sign, $name, @text) = split ' ', $_;
908db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek	print $name, $/ if $sign eq '+';
918db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    }
928db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    exit 1;
938db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek}
948db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek
958db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek##----------------------------------------------------------------------------##
96810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek# Declaration of Clang options.  Populated later.
97b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
99e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $Clang;
100810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangSB;
101810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangCXX;
102810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $ClangVersion;
103fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek
104b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
105fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
108a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
109fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1102a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my $Dir = shift @_;    
111fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
112fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
113ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    if (`uname` =~ /Darwin/) {
114ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      $Dir = $ENV{'TMPDIR'};
115ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      if (!defined $Dir) { $Dir = "/tmp"; }
116ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    }
117ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    else {
118ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      $Dir = "/tmp";
1192a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
120fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
121fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
122bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  
123bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  # Chop off any trailing '/' characters.
124bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  while ($Dir =~ /\/$/) { chop $Dir; }
125fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1272a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my @CurrentTime = localtime();  
1289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1319d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1332a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  # Determine the run number.  
1349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1362a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  if (-d $Dir) {    
1379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
13823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1392a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
1402a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    # Iterate over all files in the specified directory.    
1412a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    my $max = 0;    
1429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
14329da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1462a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    foreach my $f (@FILES) {
147fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
148fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
149fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
150fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
151fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
152fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
1549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
16923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
171fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
172fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
173445fa776d2bc9207c33a9b9ab4afb9513f6b81b0Ted Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
174fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
175fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
178fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
182fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
185fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  my $NewDir;
186fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
187fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
188fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
189fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
190fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$DateString-$RunNumber";
191fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
192fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  system 'mkdir','-p',$NewDir;
193fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  return $NewDir;
1949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
196a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
1979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
2019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
2029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2069e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek
2079e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek  if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) {
2089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
21223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
21957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
22057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
22157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
22257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
22357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
22423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
225a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
226a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2277ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2287ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
22963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
23023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
231a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
232a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
233a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
234a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
23563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
236a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
23757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
23857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2407a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2417a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2427a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2437a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2447a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2457a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2467a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2507a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2517a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2527a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
25520b2bae90c102f405ba70f602c45660ce1cd0c4eTed Kremenek  chop $Prefix while (!($x =~ /^\Q$Prefix/));
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2687a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
27063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
27263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
27363c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
27863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
28120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2847a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2854f2b10b24bab0049020d268382eda144e2aa064cTom Care# AddStatLine - Decode and insert a statistics line into the database.
2864f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
2874f2b10b24bab0049020d268382eda144e2aa064cTom Care
2884f2b10b24bab0049020d268382eda144e2aa064cTom Caresub AddStatLine {
2894f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Line  = shift;
2904f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
2914f2b10b24bab0049020d268382eda144e2aa064cTom Care
2924f2b10b24bab0049020d268382eda144e2aa064cTom Care  print $Line . "\n";
2934f2b10b24bab0049020d268382eda144e2aa064cTom Care
2944f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
2956bdda82234ff106d561dc8c0ce5ca48b97726bbfTed Kremenek      \ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
2964f2b10b24bab0049020d268382eda144e2aa064cTom Care      \ (yes|no)/x;
2974f2b10b24bab0049020d268382eda144e2aa064cTom Care
2984f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($Line !~ $Regex) {
2994f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
3004f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
3014f2b10b24bab0049020d268382eda144e2aa064cTom Care
3024f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Create a hash of the interesting fields
3034f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Row = {
3044f2b10b24bab0049020d268382eda144e2aa064cTom Care    Filename    => $1,
3054f2b10b24bab0049020d268382eda144e2aa064cTom Care    Function    => $2,
3064f2b10b24bab0049020d268382eda144e2aa064cTom Care    Total       => $3,
3074f2b10b24bab0049020d268382eda144e2aa064cTom Care    Unreachable => $4,
3084f2b10b24bab0049020d268382eda144e2aa064cTom Care    Aborted     => $5,
3094f2b10b24bab0049020d268382eda144e2aa064cTom Care    Empty       => $6
3104f2b10b24bab0049020d268382eda144e2aa064cTom Care  };
3114f2b10b24bab0049020d268382eda144e2aa064cTom Care
3124f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Add them to the stats array
3134f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @$Stats, $Row;
3144f2b10b24bab0049020d268382eda144e2aa064cTom Care}
3154f2b10b24bab0049020d268382eda144e2aa064cTom Care
3164f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
3175744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3185744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3195744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
32057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
32157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
32257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
32357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
32457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3275744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3285744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3295744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3304f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
3315744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
33257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
33357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
33457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
33557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
33657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
337fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
33857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
33920161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
34057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
34157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
34257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
34357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
34457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
345809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
34620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
347684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
348684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
34923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3505744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugType        = "";
3524f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugFile        = "";
3534f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugCategory    = "";
3544f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugDescription = "";
3554f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugPathLength  = 1;
3564f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugLine        = 0;
357ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
3585744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
359d658e67b438c60fbe3bd1773a3172fd0f082c483Ted Kremenek    last if (/<!-- BUGMETAEND -->/);
360ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
361a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek    if (/<!-- BUGTYPE (.*) -->$/) {
362a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek      $BugType = $1;
3635744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
36422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
365990c2f45e566d8ff097fa90176ba90036892b3cdTed Kremenek      $BugFile = abs_path($1);
3667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
36922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
37022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
37122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
37222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
373ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    }
374ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    elsif (/<!-- BUGCATEGORY (.*) -->$/) {
375ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $BugCategory = $1;
37622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3774f2b10b24bab0049020d268382eda144e2aa064cTom Care    elsif (/<!-- BUGDESC (.*) -->$/) {
3784f2b10b24bab0049020d268382eda144e2aa064cTom Care      $BugDescription = $1;
3794f2b10b24bab0049020d268382eda144e2aa064cTom Care    }
3805744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3815744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3825744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
383ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  
384ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  if (!defined $BugCategory) {
385ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    $BugCategory = "Other";
386ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  }
3874f2b10b24bab0049020d268382eda144e2aa064cTom Care
3884f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Don't add internal statistics to the bug reports
3894f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($BugCategory =~ /statistics/i) {
3904f2b10b24bab0049020d268382eda144e2aa064cTom Care    AddStatLine($BugDescription, $Stats);
3914f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
3924f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
3934f2b10b24bab0049020d268382eda144e2aa064cTom Care  
394a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek  push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
39581983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek                 $BugPathLength ];
39622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
39722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
39822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
3993ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek# CopyFiles - Copy resource files to target directory.
40022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
40122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
4023ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremeneksub CopyFiles {
40322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
40422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
405e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek
406e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $JS = Cwd::realpath("$RealBin/sorttable.js");
40722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
40823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
409e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $JS);  
41022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
411e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $JS, "$Dir");
41222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
41323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
41422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
4153ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek    
416e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $CSS = Cwd::realpath("$RealBin/scanview.css");
417e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
4183ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Cannot find 'scanview.css'.\n")
419e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4203ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
421e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $CSS, "$Dir");
4223ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
4233ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
424e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
4265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
4275744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
4284f2b10b24bab0049020d268382eda144e2aa064cTom Care# CalcStats - Calculates visitation statistics and returns the string.
4294f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4304f2b10b24bab0049020d268382eda144e2aa064cTom Care
4314f2b10b24bab0049020d268382eda144e2aa064cTom Caresub CalcStats {
4324f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
4334f2b10b24bab0049020d268382eda144e2aa064cTom Care
4344f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalBlocks = 0;
4354f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $UnreachedBlocks = 0;
4364f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFunctions = scalar(@$Stats);
4374f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BlockAborted = 0;
4384f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $WorkListAborted = 0;
4394f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Aborted = 0;
4404f2b10b24bab0049020d268382eda144e2aa064cTom Care
4414f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculate the unique files
4424f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $FilesHash = {};
4434f2b10b24bab0049020d268382eda144e2aa064cTom Care
4444f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $Row (@$Stats) {
4454f2b10b24bab0049020d268382eda144e2aa064cTom Care    $FilesHash->{$Row->{Filename}} = 1;
4464f2b10b24bab0049020d268382eda144e2aa064cTom Care    $TotalBlocks += $Row->{Total};
4474f2b10b24bab0049020d268382eda144e2aa064cTom Care    $UnreachedBlocks += $Row->{Unreachable};
4484f2b10b24bab0049020d268382eda144e2aa064cTom Care    $BlockAborted++ if $Row->{Aborted} eq 'yes';
4494f2b10b24bab0049020d268382eda144e2aa064cTom Care    $WorkListAborted++ if $Row->{Empty} eq 'no';
4504f2b10b24bab0049020d268382eda144e2aa064cTom Care    $Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
4514f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
4524f2b10b24bab0049020d268382eda144e2aa064cTom Care
4534f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFiles = scalar(keys(%$FilesHash));
4544f2b10b24bab0049020d268382eda144e2aa064cTom Care
4554f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculations
4564f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
4574f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
4584f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4594f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
4604f2b10b24bab0049020d268382eda144e2aa064cTom Care      $TotalFunctions * 100);
4614f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
4624f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4634f2b10b24bab0049020d268382eda144e2aa064cTom Care
4644f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
4654f2b10b24bab0049020d268382eda144e2aa064cTom Care    . " in $TotalFiles files\n"
4664f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$Aborted functions aborted early ($PercentAborted%)\n"
4674f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
4684f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
4694f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
4704f2b10b24bab0049020d268382eda144e2aa064cTom Care
4714f2b10b24bab0049020d268382eda144e2aa064cTom Care  return $StatsString;
4724f2b10b24bab0049020d268382eda144e2aa064cTom Care}
4734f2b10b24bab0049020d268382eda144e2aa064cTom Care
4744f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
4769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
4779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
478a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
4799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4804f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Dir           = shift;
4814f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BaseDir       = shift;
4824f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $AnalyzerStats = shift;
4839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
484fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
4859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
48723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
488363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
492938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @files = grep { /^report-.*\.html$/ } readdir(DIR);
4939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
4949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
495938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar(@files) == 0 and ! -e "$Dir/failures") {
49623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
49720161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
498363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
5005744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
501991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  # Scan each report file and build an index.  
5024f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Index;
5034f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Stats;
5044f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
5055744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
506938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  # Scan the failures directory and use the information in the .info files
507d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # to update the common prefix directory.
508938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @failures;
509938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @attributes_ignored;
510938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (-d "$Dir/failures") {
511938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");
512938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
513d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    closedir(DIR);
514938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");        
515938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
516938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    closedir(DIR);
517938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    foreach my $file (@failures) {
518938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
519d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      my $Path = <IN>;
520d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      if (defined $Path) { UpdatePrefix($Path); }
521d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      close IN;
522d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    }    
523d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  }
524d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  
52563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
52663c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
52763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
5285744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
5296e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
5306e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
5315744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
5325744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
5335744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
5347cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<title>${HtmlTitle}</title>
535f143545ce5ce125e7c1aa6fca9df372bfb604e9cTed Kremenek<link type="text/css" rel="stylesheet" href="scanview.css"/>
53622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
5376e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
5386e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
5396e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
5406e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
5416e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
5426e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
5436e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
5446e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
5456e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5466e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
547ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
5482350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenekfunction CopyCheckedStateToCheckButtons(SummaryCheckButton) {
5492350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  var Inputs = document.getElementsByTagName("input");
5502350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  for ( var i = 0 ; i < Inputs.length; ++i ) {
5512350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    if (Inputs[i].type == "checkbox") {
5522350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      if(Inputs[i] != SummaryCheckButton) {
5532350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].checked = SummaryCheckButton.checked;
5542350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].onclick();
5552350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek	  }
5562350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    }
5572350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  }
5582350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek}
5592350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek
560999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekfunction returnObjById( id ) {
561999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (document.getElementById) 
562999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.getElementById(id);
563999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.all)
564999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.all[id];
565999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.layers) 
566999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.layers[id];
567999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    return returnVar; 
568999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek}
569999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
570999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekvar NumUnchecked = 0;
571999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
5726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
5736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
5746e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
575999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (--NumUnchecked == 0) {
576999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek      returnObjById("AllBugsCheck").checked = true;
577999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    }
5786e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5796e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
5806e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
581999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    NumUnchecked++;
582999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    returnObjById("AllBugsCheck").checked = false;
5836e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5846e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
5856e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
5861d1abb1dec3d0b7609809d876a16a64a021e96e7Ted Kremenek<!-- SUMMARYENDHEAD -->
5876e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
5886e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
5897cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h1>${HtmlTitle}</h1>
5907cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5917cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<table>
5927cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
5937cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
5947cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
595b4882d50923881d1a01af4d5604b5baaa141cdf9Douglas Gregor<tr><th>Clang Version:</th><td>${ClangVersion}</td></tr>
5967cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Date:</th><td>${Date}</td></tr>
5977cba11262458df05951432b54997eb40a35dbf9eTed KremenekENDTEXT
5987cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5997cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
6007cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if (defined($BuildName) && defined($BuildDate));
6017cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6027cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT <<ENDTEXT;
6037cba11262458df05951432b54997eb40a35dbf9eTed Kremenek</table>
6046e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6056e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
606991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files)) {
607991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Print out the summary table.
608991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my %Totals;
609ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
610991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( @Index ) {
611ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_type = ($row->[2]);
612ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_category = ($row->[1]);
613ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $key = "$bug_category:$bug_type";
614ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
615ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
616ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else { $Totals{$key}->[0]++; }
6176e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
618991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6197cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    print OUT "<h2>Bug Summary</h2>";
620991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
621991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $BuildName) {
622991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
6236e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
624f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
6252350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  my $TotalBugs = scalar(@Index);
6266e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
627ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table>
628ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
629999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed 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>
6306e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6316e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
632ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    my $last_category;
633ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
634ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $key (
635ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      sort {
636ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $x = $Totals{$a};
637ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $y = $Totals{$b};
638ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $res = $x->[1] cmp $y->[1];
639ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res = $x->[2] cmp $y->[2] if ($res == 0);
640ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res
641ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      } keys %Totals ) 
642ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    {
643ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $val = $Totals{$key};
644ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $category = $val->[1];
645ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $last_category or $last_category ne $category) {
646ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $last_category = $category;
647ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
648ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }      
649ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = lc $key;
650ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
651ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr><td class=\"SUMM_DESC\">";
652ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[2];
6532350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      print OUT "</td><td class=\"Q\">";
654ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[0];
655ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
656991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
6576e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6586e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
6596e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6606e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
6616e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
6627cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h2>Reports</h2>
663ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
664ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table class="sortable" style="table-layout:automatic">
665ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr>
666ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td>Bug Group</td>
667ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
668bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
669ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="Q">Line</td>
67081983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek  <td class="Q">Path Length</td>
6712645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
672ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <!-- REPORTBUGCOL -->
673ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek</tr></thead>
674ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<tbody>
6755744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
6769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
677991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $prefix = GetPrefix();
678991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $regex;
679991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFileRegex;
680991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFilePrefix = "File:</td><td>";
6817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
682991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $prefix) { 
683991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $regex = qr/^\Q$prefix\E/is;    
684991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
685991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }    
6867a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
687ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
688ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = "$row->[1]:$row->[2]";
689ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x = lc $x;
690ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
6916e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
692991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $ReportFile = $row->[0];
693ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          
694ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr class=\"bt_$x\">";
695ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
696991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT $row->[1];
697ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
698ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
699ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $row->[2];
700ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
701ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
702ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Update the file prefix.      
703ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $fname = $row->[3];
704ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
705991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (defined $regex) {
706991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $fname =~ s/$regex//;
707991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
708991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
709ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
71091639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      print OUT "<td>";      
711ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my @fname = split /\//,$fname;
712ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if ($#fname > 0) {
713ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        while ($#fname >= 0) {
714ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          my $x = shift @fname;
715ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          print OUT $x;
716ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          if ($#fname >= 0) {
717ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek            print OUT "<span class=\"W\"> </span>/";
718ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          }
719ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        }
720ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
721ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else {
722ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT $fname;
72391639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      }      
724ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
725ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
726ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Print out the quantities.
72781983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for my $j ( 4 .. 5 ) {
728ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td class=\"Q\">$row->[$j]</td>";        
729ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
730ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
731991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Print the rest of the columns.
73281983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for (my $j = 6; $j <= $#{$row}; ++$j) {
733ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td>$row->[$j]</td>"
734991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
7357f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
736991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Emit the "View" link.
73768005ddb49b88c2f6cdd88185d72d8b411d2dbc9Ted Kremenek      print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
7383cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
739e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar      # Emit REPORTBUG markers.
740ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
741e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar        
742991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # End the row.
743991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</tr>\n";
744991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
745991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
746ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    print OUT "</tbody>\n</table>\n\n";
747991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  }
748991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
749938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar (@failures) || scalar(@attributes_ignored)) {
750938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    print OUT "<h2>Analyzer Failures</h2>\n";
751938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
752938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @attributes_ignored) {
753938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "The analyzer's parser ignored the following attributes:<p>\n";
754938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
755938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
756938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @attributes_ignored) {
757938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
758938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $attribute = $1;
759938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the attribute file to get the first file that failed.
760938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (!open (ATTR, "$Dir/failures/$file"));
761938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile = <ATTR>;
762938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $ppfile;
763938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close ATTR;
764938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (! -e "$Dir/failures/$ppfile");
765938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the info file and get the name of the source file.
766938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$ppfile.info.txt") or
767938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$ppfile.info.txt\n";
768938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $srcfile = <INFO>;
769938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $srcfile;
770938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close (INFO);
771938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Print the information in the table.
772938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $prefix = GetPrefix();
773938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
774938eef139ad43345248235da31f78a759dd18f13Ted 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";
775938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile_clang = $ppfile;
776938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
777938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
778938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      }
779938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
780938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }
781938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
782938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @failures) {
783938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<p>The analyzer had problems processing the following files:</p>\n";
784938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
785938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
786938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @failures) {
78782a1253077cd0832e4d347062b911cd305ab62d1Ted Kremenek        $file =~ /(.+).info.txt$/;
788991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Get the preprocessed file.
789991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $ppfile = $1;
790991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Open the info file and get the name of the source file.
791938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$file") or
792938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$file\n";
793991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $srcfile = <INFO>;
7945d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $srcfile;
7955d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        my $problem = <INFO>;
7965d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $problem;
797991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        close (INFO);
798991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Print the information in the table.
799d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        my $prefix = GetPrefix();
8009f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
801938eef139ad43345248235da31f78a759dd18f13Ted 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";
802ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        my $ppfile_clang = $ppfile;
803ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
804938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
805991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
806938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
807938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }    
808e2c8663ad2b110712401145b866072bb94108058Nico 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";
8095744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
8105744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
811991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  print OUT "</body></html>\n";  
8125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
8133ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  CopyFiles($Dir);
81420161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
81520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
81620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
817fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
81820161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
8194f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Print statistics
8204f2b10b24bab0049020d268382eda144e2aa064cTom Care  print CalcStats(\@Stats) if $AnalyzerStats;
8214f2b10b24bab0049020d268382eda144e2aa064cTom Care
82223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
823150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
824150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
8255950b3f93a6e8a6ae8bd59a0ef5797e9f88f0bc3Ted Kremenek    Diag("Run 'scan-view $Dir' to examine bug reports.\n");
826150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
827363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
828938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
829991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
830363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
8319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
834dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
835dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
836dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
8376b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
8386b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
8396b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
8406b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
8416b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8426b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
8436b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
8446b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
8456b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
8466b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
8476b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8486b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8496b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
8506b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
8516b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8526b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
8536b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
854cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremeneksub SetEnv {
855cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift @_;
856cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  foreach my $opt ('CC', 'CXX', 'CLANG', 'CLANG_CXX',
857cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS') {
858cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    die "$opt is undefined\n" if (!defined $opt);
859cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{$opt} = $Options->{$opt};
860cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
861cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  foreach my $opt ('CCC_ANALYZER_STORE_MODEL',
862cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_PLUGINS',
863cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_INTERNAL_STATS',
864cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                    'CCC_ANALYZER_OUTPUT_FORMAT') {
865cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    my $x = $Options->{$opt};
866cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    if (defined $x) { $ENV{$opt} = $x }
867cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
868cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Verbose = $Options->{'VERBOSE'};
869cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  if ($Verbose >= 2) {
870cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
871cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
872cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  if ($Verbose >= 3) {
873cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    $ENV{'CCC_ANALYZER_LOG'} = 1;
874cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  }
875cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek}
876cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
87738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremeneksub RunXcodebuild {
87838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $Args = shift;
87938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $IgnoreErrors = shift;
88038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $CCAnalyzer = shift;
88138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  my $CXXAnalyzer = shift;
882cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift;
883cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
88438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if ($IgnoreErrors) {
88538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
88638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
88738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
888cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  # Default to old behavior where we insert a bogus compiler.
889cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  SetEnv($Options);
890cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  
89138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # Check if using iPhone SDK 3.0 (simulator).  If so the compiler being
89238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # used should be gcc-4.2.
89338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if (!defined $ENV{"CCC_CC"}) {
89438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
89538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek      if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
89638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek        if (@$Args[$i+1] =~ /^iphonesimulator3/) {
89738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek          $ENV{"CCC_CC"} = "gcc-4.2";
898cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek          $ENV{"CCC_CXX"} = "g++-4.2";
89938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek        }
90038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek      }
90138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek    }
90238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
90338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek
90438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # Disable PCH files until clang supports them.
90538447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
90638447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
90738447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
90838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
90938447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  # (via c++-analyzer) when linking such files.
91038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
91138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek 
91238447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  return (system(@$Args) >> 8); 
91338447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek}
91438447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek
915cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremeneksub RunBuildCommand {  
916dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
9177442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
918dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
9196195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
920524c308506e77e173092e87a0724a27817311428Ted Kremenek  my $CXXAnalyzer = shift;
921cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  my $Options = shift;
922dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
9233301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
9243301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
9253301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
9263301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
9273301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
92838447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  if ($Cmd eq "xcodebuild") {
929cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek    return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options);
93038447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  }
93138447a40795ef140a5d14ce43e31b60276c8d207Ted Kremenek  
932cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  # Setup the environment.
933cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  SetEnv($Options);
934cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  
93592548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek  if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or 
93692548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?cc[^\/]*$)/ or
93792548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
93805acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek      $Cmd =~ /(.*\/?clang$)/ or 
93992548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
94092548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek
94192548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
94251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CC"} = $1;      
94392548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    }
94492548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek        
945dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
9466195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
947dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
94851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  elsif ($Cmd =~ /(.*\/?g\+\+[^\/]*$)/ or 
94951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+[^\/]*$)/ or
95051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?llvm-g\+\+[^\/]*$)/ or
95105acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek        $Cmd =~ /(.*\/?clang\+\+$)/ or
95251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+-analyzer[^\/]*$)/) {
95351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    if (!($Cmd =~ /c\+\+-analyzer/) and !defined $ENV{"CCC_CXX"}) {
95451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CXX"} = $1;      
95551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    }        
95651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    shift @$Args;
957524c308506e77e173092e87a0724a27817311428Ted Kremenek    unshift @$Args, $CXXAnalyzer;
95851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  }
9597442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
9607442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
9616fba85dc6509069ff7735283464bd02da2da6eebTed Kremenek      AddIfNotPresent($Args, "CC=$CCAnalyzer");
962524c308506e77e173092e87a0724a27817311428Ted Kremenek      AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
9636b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
9648912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
9657442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
9666b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
96787752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek
9685a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
969dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
970dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
971dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
9729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
9739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
9749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
975a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
9769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
9775744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
978a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
9792b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
980f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
981f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
982fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
983f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
984f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
985f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
986f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
9872b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
9882b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
989eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -analyze-headers
9908382cf57b722f130f1a6b45380639871c07271c1Ted Kremenek 
991eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Also analyze functions in #included files.  By default, such functions
992eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   are skipped unless they are called by functions within the main source file.
993eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
994eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -o <output location>
995eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
996eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specifies the output directory for analyzer reports. Subdirectories will be
997eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   created as needed to represent separate "runs" of the analyzer. If this
998eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   option is not specified, a directory is created in /tmp (TMPDIR on Mac OS X)
999eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   to store the reports.
1000eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1001eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -h             
1002363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
10031262fc4d66584224234691d30d779f8ff004585cTed Kremenek
1004eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Display this message.
1005eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1006eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -k
1007eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --keep-going
1008eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek				  
1009eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Add a "keep on going" option to the specified build command. This option
1010eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   currently supports make and xcodebuild. This is a convenience option; one
1011eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   can specify this behavior directly using build options.
1012eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1013eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --html-title [title]
1014eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --html-title=[title]
10152b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1016eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specify the title used on generated HTML pages. If not specified, a default
1017eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   title will be used.
10187cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1019eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -plist
10202c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
1021eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default the output of scan-build is a set of HTML files. This option
1022eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   outputs the results as a set of .plist files.
10232c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
1024eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -plist-html
1025eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1026eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default the output of scan-build is a set of HTML files. This option
1027eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   outputs the results as a set of HTML and .plist files.
1028eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1029eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --status-bugs
1030eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1031eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   By default, the exit status of scan-build is the same as the executed build
1032eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   command. Specifying this option causes the exit status of scan-build to be 1
1033eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   if it found potential bugs and 0 otherwise.
1034386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
1035eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-cc [compiler path]   
1036eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-cc=[compiler path]
1037eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1038eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   scan-build analyzes a project by interposing a "fake compiler", which
1039eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   executes a real compiler for compilation and the static analyzer for analysis.
1040eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Because of the current implementation of interposition, scan-build does not
1041eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   know what compiler your project normally uses.  Instead, it simply overrides
1042eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   the CC environment variable, and guesses your default compiler.
1043eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   
1044eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   In the future, this interposition mechanism to be improved, but if you need
1045eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   scan-build to use a specific compiler for *compilation* then you can use
1046eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   this option to specify a path to that compiler.
1047eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek
1048eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-c++ [compiler path]
1049eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --use-c++=[compiler path]
1050eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1051eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   This is the same as "-use-cc" but for C++ code.
1052eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1053eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -v
1054eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1055eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Enable verbose output from scan-build. A second and third '-v' increases
1056eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   verbosity.
1057f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
1058eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -V
1059eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek --view
1060363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
1061eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   View analysis results in a web browser when the build completes.
10627f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
1063be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed KremenekADVANCED OPTIONS:
1064be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
1065eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -no-failure-reports
1066eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1067eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Do not create a 'failures' subdirectory that includes analyzer crash reports
1068eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   and preprocessed source files.
1069b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1070eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -stats
1071eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1072eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Generates visitation statistics for the project being analyzed.
10734f2b10b24bab0049020d268382eda144e2aa064cTom Care
1074eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -maxloop <loop count>
10751e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks 
1076eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Specifiy the number of times a block can be visited before giving up.
1077eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Default is 4. Increase for more comprehensive coverage at a cost of speed.
1078eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek  
1079eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek -internal-stats
1080eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek 
1081eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek   Generate internal analyzer statistics.
1082810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 
10835a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek --use-analyzer [Xcode|path to clang] 
10845a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek --use-analyzer=[Xcode|path to clang]
1085810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 
1086810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   scan-build uses the 'clang' executable relative to itself for static
1087810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   analysis. One can override this behavior with this option by using the
1088810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   'clang' packaged with Xcode (on OS X) or from the PATH.
1089810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  
109009fbf297da918760ce33302a3f709a77f43af265Ted KremenekCONTROLLING CHECKERS:
109109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
109209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek A default group of checkers are always run unless explicitly disabled.
109309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek Checkers may be enabled/disabled using the following options:
109409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
109509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -enable-checker [checker name]
109609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -disable-checker [checker name]
1097f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks 
1098f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna ZaksLOADING CHECKERS:
1099f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1100f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks Loading external checkers using the clang plugin interface:
1101f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1102f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks -load-plugin [plugin library]
1103d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
1104b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1105ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for list of checkers that are enabled.
1106f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1107f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# create a list to load the plugins via the 'Xclang' command line
1108f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# argument
1109f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginLoadCommandline_xclang;
1110f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksforeach my $param ( @PluginsToLoad ) {
1111f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, "-Xclang" );
1112f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, $param );
1113f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks}
1114ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy %EnabledCheckers;
1115ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekforeach my $lang ("c", "objective-c", "objective-c++", "c++") {
1116ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  pipe(FROM_CHILD, TO_PARENT);
1117ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $pid = fork();
1118ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if ($pid == 0) {
1119ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    close FROM_CHILD;
1120ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDOUT,">&", \*TO_PARENT);
1121ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDERR,">&", \*TO_PARENT);
1122f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###'); 
1123ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1124ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(TO_PARENT);
1125ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1126ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    foreach my $val (split /\s+/) {
1127ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $val =~ s/\"//g;
1128ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($val =~ /-analyzer-checker\=([^\s]+)/) {
1129ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $EnabledCheckers{$1} = 1;
1130ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1131ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1132ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1133ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  waitpid($pid,0);
1134ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(FROM_CHILD);
1135ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1136ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1137ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for complete list of checkers.
1138ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekpipe(FROM_CHILD, TO_PARENT);
1139ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $pid = fork();
1140ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif ($pid == 0) {
1141ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close FROM_CHILD;
1142ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  open(STDOUT,">&", \*TO_PARENT);
1143ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  open(STDERR,">&", \*TO_PARENT);
1144f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
1145ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1146ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekclose(TO_PARENT);
1147ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $foundCheckers = 0;
1148ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekwhile(<FROM_CHILD>) {
1149ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if (/CHECKERS:/) {
1150ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $foundCheckers = 1;
1151ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    last;
1152ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1153ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1154ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!$foundCheckers) {
1155ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  print "  *** Could not query Clang for the list of available checkers.";
1156ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1157ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekelse {
1158ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  print("\nAVAILABLE CHECKERS:\n\n");
115973078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek  my $skip = 0;
1160ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
116173078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek    if (/experimental/) {
116273078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek      $skip = 1;
116373078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek      next;
116473078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek    }
116573078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek    if ($skip) {
116673078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek      next if (!/^\s\s[^\s]/);
116773078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek      $skip = 0;
116873078642d3c32499ee573bd458af6d384fa7f6d8Ted Kremenek    }
1169ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    s/^\s\s//;
1170ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    if (/^([^\s]+)/) {
1171ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      # Is the checker enabled?
1172ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $checker = $1;
1173ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $enabled = 0;
1174ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $aggregate = "";
1175ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      foreach my $domain (split /\./, $checker) {
1176ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $aggregate .= $domain;
1177ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        if ($EnabledCheckers{$aggregate}) {
1178ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek          $enabled =1;
1179ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek          last;
1180f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks        }
1181f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks        # append a dot, if an additional domain is added in the next iteration
1182f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks        $aggregate .= ".";
1183ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1184ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      
1185ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($enabled) {
1186ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print " + ";
1187ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1188ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      else {
1189ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print "   ";
1190ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1191ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1192ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    else {
1193ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      print "   ";
1194ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1195ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    print $_;
1196ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  } 
1197ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1198ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekwaitpid($pid,0);
1199ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekclose(FROM_CHILD);
12007fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1201b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
1202b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1203ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek NOTE: "+" indicates that an analysis is enabled by default.
1204b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
12052b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
12062b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1207363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
120839eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
12095744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
12102b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1211eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenek scan-build -o /tmp/myhtmldir make -j4
12122b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
1213eaafdfc7b475937ed194ad729407481054b99be9Ted KremenekThe above example causes analysis reports to be deposited into a subdirectory
1214eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenekof "/tmp/myhtmldir" and to run "make" with the "-j4" option. A different
1215eaafdfc7b475937ed194ad729407481054b99be9Ted Kremeneksubdirectory is created each time scan-build analyzes a project. The analyzer
1216eaafdfc7b475937ed194ad729407481054b99be9Ted Kremenekshould support most parallel builds, but not distributed builds.
12172b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
12182b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
12199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
12209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
12227cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# HtmlEscape - HTML entity encode characters that are special in HTML
12237cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12247cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12257cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub HtmlEscape {
12267cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
12277cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
12287cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $tmp = $arg;
122987f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/&/&amp;/g;
123087f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/</&lt;/g;
123187f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/>/&gt;/g;
12327cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  return $tmp;
12337cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
12347cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12357cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12367cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# ShellEscape - backslash escape characters that are special to the shell
12377cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12387cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12397cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub ShellEscape {
12407cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
12417cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
124287f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
124387f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  return $arg;
12447cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
12457cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12467cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
12479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
12489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
12499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1250e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekmy $AnalyzeHeaders = 0;
12519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
12529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
12537f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
1254363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
1255b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
125607c3767be59472e19183c7b51fae76481465cb51Zhongxing Xumy $StoreModel;
1257be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekmy $ConstraintsModel;
12581e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaksmy $InternalStats;
12598d8bc9157fccab6a4089c41cdad9e12045edd736Ted Kremenekmy $OutputFormat = "html";
12604f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $AnalyzerStats = 0;
12614f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $MaxLoop = 0;
12629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
12649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1265a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
12669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
12679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1268ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1269ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $displayHelp = 0;
1270810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekmy $AnalyzerDiscoveryMethod;
1271ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
12729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
12739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
12759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
12779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12782f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
1279ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $displayHelp = 1;
1280ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    shift @ARGV;
1281ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    next;
12829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1284e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  if ($arg eq '-analyze-headers') {
1285e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    shift @ARGV;    
1286e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    $AnalyzeHeaders = 1;
1287e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    next;
1288e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  }
1289e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
12909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
12919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
12929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
12939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
129423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
12959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
12969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1297db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # Construct an absolute path.  Uses the current working directory
1298db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # as a base if the original path was not absolute.
1299db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    $HtmlDir = abs_path(shift @ARGV);
1300db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    
13019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13037cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13047cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--html-title(=(.+))?$/) {
13057cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    shift @ARGV;
13067cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1307278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq '') {
13087cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      if (!@ARGV) {
13097cba11262458df05951432b54997eb40a35dbf9eTed Kremenek        DieDiag("'--html-title' option requires a string.\n");
13107cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      }
13117cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13127cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = shift @ARGV;
13137cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    } else {
13147cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = $2;
13157cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    }
13167cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
13177cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    next;
13187cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  }
13199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13202b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
13219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
13239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13257fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1326f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
1327f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
1328f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
1329f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1330278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1331f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
1332f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
1333f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
1334f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
1335f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1336f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
1337f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
1338f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1339f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1340f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
1341f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
1342f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
1343f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
13447cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
1345386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
134651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    my $cxx;    
1347386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
1348278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1349386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
1350386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
1351386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
135251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = shift @ARGV;
1353386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
1354386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
135551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = $2;
1356386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
135751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    
135851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    $ENV{"CCC_CXX"} = $cxx;
1359386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
1360386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
1361386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
13629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
13639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
13659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13687f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
13697f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
13707f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
13717f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
13727f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
13737f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
1374363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
1375363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
1376363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
1377363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
1378363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
137907c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu
138007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  if ($arg eq "-store") {
138107c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    shift @ARGV;
1382be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $StoreModel = shift @ARGV;
1383be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    next;
1384be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  }
1385be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  
1386be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  if ($arg eq "-constraints") {
1387be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    shift @ARGV;
1388be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $ConstraintsModel = shift @ARGV;
138907c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    next;
139007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  }
13911e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks
13921e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks  if ($arg eq "-internal-stats") {
13931e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    shift @ARGV;
13941e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    $InternalStats = 1;
13951e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks    next;
13961e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks  }
1397363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
1398db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  if ($arg eq "-plist") {
1399db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    shift @ARGV;
1400db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    $OutputFormat = "plist";
1401db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    next;
1402db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
14037753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  if ($arg eq "-plist-html") {
14047753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    shift @ARGV;
14057753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    $OutputFormat = "plist-html";
14067753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    next;
14077753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  }
1408e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  
1409e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  if ($arg eq "-no-failure-reports") {
1410e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    $ENV{"CCC_REPORT_FAILURES"} = 0;
1411e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    next;
1412e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  }
14134f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-stats") {
14144f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
14154f2b10b24bab0049020d268382eda144e2aa064cTom Care    $AnalyzerStats = 1;
14164f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
14174f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
14184f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-maxloop") {
14194f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
14204f2b10b24bab0049020d268382eda144e2aa064cTom Care    $MaxLoop = shift @ARGV;
14214f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
14224f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
142309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-enable-checker") {
142409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
142509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-checker", shift @ARGV;
142609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
142709fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
142809fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-disable-checker") {
142909fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
143009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV;
143109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
143209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
1433f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  if ($arg eq "-load-plugin") {
1434f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    shift @ARGV;
1435f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    push @PluginsToLoad, "-load", shift @ARGV;
1436f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    next;
1437f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  }
14385a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek  if ($arg eq "--use-analyzer") {
1439810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek 	shift @ARGV;
1440810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  	$AnalyzerDiscoveryMethod = shift @ARGV;
1441810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	next;
1442810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
14435a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek  if ($arg =~ /^--use-analyzer=(.+)$/) {
1444810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    shift @ARGV;
1445810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	$AnalyzerDiscoveryMethod = $1;
1446810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	next;
1447810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1448f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  
144923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
14500062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
14519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
14529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
14539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1454ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!@ARGV and $displayHelp == 0) {
145523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
1456ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  $displayHelp = 1;
1457ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1458ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1459ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif ($displayHelp) {
14609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1461a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
14629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
14639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1464810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek# Find 'clang'
1465810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekif (!defined $AnalyzerDiscoveryMethod) {
1466810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  $Clang = Cwd::realpath("$RealBin/bin/clang");
1467810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  if (!defined $Clang || ! -x $Clang) {
1468810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = Cwd::realpath("$RealBin/clang");
1469810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1470810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  if (!defined $Clang || ! -x $Clang) {
1471810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    DieDiag("error: Cannot find an executable 'clang' relative to scan-build." .
14725a3581daf22f9b9d0025093b07c35a08cceeae6cTed Kremenek   	        "  Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n");
1473810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1474810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek} 
1475810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenekelse {  
14760d3a3fd7211a1b368d1f8c0d7ca1cfd40d31a0eaTed Kremenek  if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) {
1477810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	my $xcrun = `which xcrun`;
1478810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    chomp $xcrun;
1479810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	if ($xcrun eq "") {
1480810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  	  DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n");
1481810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	}
1482810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = `$xcrun -toolchain XcodeDefault -find clang`;
1483810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    chomp $Clang;  
1484810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    if ($Clang eq "") {
1485810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek      DieDiag("No 'clang' executable found by 'xcrun'\n"); 
1486810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    }
1487810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1488810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  else {
1489810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek    $Clang = Cwd::realpath($AnalyzerDiscoveryMethod);
1490810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	if (! -x $Clang) {
1491810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek   	  DieDiag("Cannot find an executable clang at '$Clang'\n");
1492810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek	}
1493810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek  }
1494810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek}
1495810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek
1496810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX = $Clang;
1497810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX =~ s/\-\d+\.\d+$//;
1498810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangCXX .= "++";
1499810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek$ClangVersion = HtmlEscape(`$Clang --version`);
1500810e6229e59796f8109e94e4a469a2dc17cf3e6dTed Kremenek
1501ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine where results go.
15027cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
15037cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
15047cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  unless (defined($HtmlTitle));
1505386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
15069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
1507684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
1508a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
15099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1510ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine the location of ccc-analyzer.
151151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $AbsRealBin = Cwd::realpath($RealBin);
151251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $Cmd = "$AbsRealBin/libexec/ccc-analyzer";
151351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $CmdCXX = "$AbsRealBin/libexec/c++-analyzer";
151451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek
1515ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenekif (!defined $Cmd || ! -x $Cmd) {
151651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $Cmd = "$AbsRealBin/ccc-analyzer";
15176b89636db873142f562cf576df9bc195c5b8674bTed Kremenek  DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
1518ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenek}
151951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekif (!defined $CmdCXX || ! -x $CmdCXX) {
152051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $CmdCXX = "$AbsRealBin/c++-analyzer";
152151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
152251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek}
1523f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
1524810e6229e59796f8109e94e4a469a2dc17cf3e6dTed KremenekDiag("Using '$Clang' for static analysis\n");
15250b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
1526ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted KremenekSetHtmlEnv(\@ARGV, $HtmlDir);
1527cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekif ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; }
1528cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekif ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; }
1529be92debbf1e9c38b1ae8a4a9c30377b24196ca73Ted Kremenekif ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; }
1530cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek
1531cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek# Delay setting up other environment variables in case we can do true
1532cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek# interposition.
1533cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $CCC_ANALYZER_ANALYSIS = join ' ',@AnalysesToRun;
1534cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $CCC_ANALYZER_PLUGINS = join ' ',@PluginsToLoad;
1535cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy %Options = (
1536cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CC' => $Cmd,
1537cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CXX' => $CmdCXX,
1538cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CLANG' => $Clang,
1539cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CLANG_CXX' => $ClangCXX,
1540cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'VERBOSE' => $Verbose,
1541cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CCC_ANALYZER_ANALYSIS' => $CCC_ANALYZER_ANALYSIS,
1542cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'CCC_ANALYZER_PLUGINS' => $CCC_ANALYZER_PLUGINS,
1543cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  'OUTPUT_DIR' => $HtmlDir
1544cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek);
1545f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
15463cab2b1c3798f2a6aa3526875801a02aebf6fc1dZhongxing Xuif (defined $StoreModel) {
1547cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
154807c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu}
1549be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekif (defined $ConstraintsModel) {
1550cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
1551be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek}
15521e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaksif (defined $InternalStats) {
1553cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_INTERNAL_STATS'} = 1;
15541e548f12f7cd6631a3e688a9580ede92898d9e69Anna Zaks}
1555db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenekif (defined $OutputFormat) {
1556cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek  $Options{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
1557db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek}
1558db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
15599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
1560cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX,
1561cbea860417eea485be5bc34e6a61f267cf180a56Ted Kremenek                                \%Options);
15629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
15637753b352366778d01c5cda4117356f181d3dd468Ted Kremenekif (defined $OutputFormat) {
15641182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  if ($OutputFormat =~ /plist/) {
15651182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis run complete.\n";
15661182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
15671182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  }
15681182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  elsif ($OutputFormat =~ /html/) {
15697753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    # Postprocess the HTML directory.
15704f2b10b24bab0049020d268382eda144e2aa064cTom Care    my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
15717753b352366778d01c5cda4117356f181d3dd468Ted Kremenek
15727753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ViewResults and -r "$HtmlDir/index.html") {
15737753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Analysis run complete.\n";
15747753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
15757753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      my $ScanView = Cwd::realpath("$RealBin/scan-view");
15767753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      if (! -x $ScanView) { $ScanView = "scan-view"; }
15777753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exec $ScanView, "$HtmlDir";
15787753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1579db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
15807753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ExitStatusFoundBugs) {
15817753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 1 if ($NumBugs > 0);
15827753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 0;
15837753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1584db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
1585363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
1586363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
15875656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
15885656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
1589