scan-build revision f8e8a3eeff891d1c056c96b6d6be404533741ba7
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'};
310e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $UseColor = (defined $TERM and $TERM eq '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##----------------------------------------------------------------------------##
96b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Some initial preprocessing of Clang options.
97b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
992a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek# Find 'clang'
100fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenekmy $ClangSB = Cwd::realpath("$RealBin/bin/clang");
1018d10cdd9aa1d58f1898adf7752a7026f151ebc04Ted Kremenekif (!defined $ClangSB || ! -x $ClangSB) {
102fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek  $ClangSB = Cwd::realpath("$RealBin/clang");
103fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek}
104e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $Clang;
105e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekif (!defined $ClangSB || ! -x $ClangSB) {
106e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenek  # Default to looking for 'clang' in the path.
1076492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  $Clang = `which clang`;
1086492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  chomp $Clang;
1096492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  if ($Clang eq "") {
1108db26ce0464c712058ab60b72e2a70c04148020eTed Kremenek    DieDiag("No 'clang' executable found in path.\n");
1116492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  }
1122a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek}
113e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekelse {
114e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenek  $Clang = $ClangSB;
115e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenek}
116e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $ClangCXX = $Clang . "++";
117b4882d50923881d1a01af4d5604b5baaa141cdf9Douglas Gregormy $ClangVersion = HtmlEscape(`$Clang --version`);
118fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek
119b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
120fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
123a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
124fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1252a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my $Dir = shift @_;    
126fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
127fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
128ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    if (`uname` =~ /Darwin/) {
129ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      $Dir = $ENV{'TMPDIR'};
130ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      if (!defined $Dir) { $Dir = "/tmp"; }
131ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    }
132ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    else {
133ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      $Dir = "/tmp";
1342a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
135fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
136fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
137bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  
138bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  # Chop off any trailing '/' characters.
139bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  while ($Dir =~ /\/$/) { chop $Dir; }
140fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1422a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my @CurrentTime = localtime();  
1439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1469d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1482a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  # Determine the run number.  
1499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1512a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  if (-d $Dir) {    
1529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
15323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1542a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
1552a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    # Iterate over all files in the specified directory.    
1562a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    my $max = 0;    
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
15829da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1612a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    foreach my $f (@FILES) {
162fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
163fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
164fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
165fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
166fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
167fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
1699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
18423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
186fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
187fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
188445fa776d2bc9207c33a9b9ab4afb9513f6b81b0Ted Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
189fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
190fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
193fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
197fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
200fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  my $NewDir;
201fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
202fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
203fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
204fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
205fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$DateString-$RunNumber";
206fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
207fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  system 'mkdir','-p',$NewDir;
208fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  return $NewDir;
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
211a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
2169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
2179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2219e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek
2229e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek  if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) {
2239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
22723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
23457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
23557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
23657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
23857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
23923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
240a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
241a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2427ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2437ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
24463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
24523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
246a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
247a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
248a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
249a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
25063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
251a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
25257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
25357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
25457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2687a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
27020b2bae90c102f405ba70f602c45660ce1cd0c4eTed Kremenek  chop $Prefix while (!($x =~ /^\Q$Prefix/));
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2847a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
28563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2867a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
28763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
28863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2897a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2907a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2917a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2927a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
29363c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2947a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2957a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
29620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2977a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2987a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2997a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
3004f2b10b24bab0049020d268382eda144e2aa064cTom Care# AddStatLine - Decode and insert a statistics line into the database.
3014f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
3024f2b10b24bab0049020d268382eda144e2aa064cTom Care
3034f2b10b24bab0049020d268382eda144e2aa064cTom Caresub AddStatLine {
3044f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Line  = shift;
3054f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
3064f2b10b24bab0049020d268382eda144e2aa064cTom Care
3074f2b10b24bab0049020d268382eda144e2aa064cTom Care  print $Line . "\n";
3084f2b10b24bab0049020d268382eda144e2aa064cTom Care
3094f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
3106bdda82234ff106d561dc8c0ce5ca48b97726bbfTed Kremenek      \ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
3114f2b10b24bab0049020d268382eda144e2aa064cTom Care      \ (yes|no)/x;
3124f2b10b24bab0049020d268382eda144e2aa064cTom Care
3134f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($Line !~ $Regex) {
3144f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
3154f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
3164f2b10b24bab0049020d268382eda144e2aa064cTom Care
3174f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Create a hash of the interesting fields
3184f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Row = {
3194f2b10b24bab0049020d268382eda144e2aa064cTom Care    Filename    => $1,
3204f2b10b24bab0049020d268382eda144e2aa064cTom Care    Function    => $2,
3214f2b10b24bab0049020d268382eda144e2aa064cTom Care    Total       => $3,
3224f2b10b24bab0049020d268382eda144e2aa064cTom Care    Unreachable => $4,
3234f2b10b24bab0049020d268382eda144e2aa064cTom Care    Aborted     => $5,
3244f2b10b24bab0049020d268382eda144e2aa064cTom Care    Empty       => $6
3254f2b10b24bab0049020d268382eda144e2aa064cTom Care  };
3264f2b10b24bab0049020d268382eda144e2aa064cTom Care
3274f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Add them to the stats array
3284f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @$Stats, $Row;
3294f2b10b24bab0049020d268382eda144e2aa064cTom Care}
3304f2b10b24bab0049020d268382eda144e2aa064cTom Care
3314f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
3325744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3335744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3345744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
33557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
33657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
33757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
33857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
33957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3405744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3415744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3425744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3435744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3445744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3454f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
3465744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
34757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
34857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
34957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
35057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
35157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
352fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
35357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
35420161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
35557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
35657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
35757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
35857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
35957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
360809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
36120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
362684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
363684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
36423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3655744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3664f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugType        = "";
3674f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugFile        = "";
3684f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugCategory    = "";
3694f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugDescription = "";
3704f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugPathLength  = 1;
3714f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugLine        = 0;
372ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
3735744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
374d658e67b438c60fbe3bd1773a3172fd0f082c483Ted Kremenek    last if (/<!-- BUGMETAEND -->/);
375ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
376a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek    if (/<!-- BUGTYPE (.*) -->$/) {
377a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek      $BugType = $1;
3785744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
37922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
380990c2f45e566d8ff097fa90176ba90036892b3cdTed Kremenek      $BugFile = abs_path($1);
3817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
38222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
38322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
38422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
38522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
38622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
38722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
388ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    }
389ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    elsif (/<!-- BUGCATEGORY (.*) -->$/) {
390ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $BugCategory = $1;
39122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3924f2b10b24bab0049020d268382eda144e2aa064cTom Care    elsif (/<!-- BUGDESC (.*) -->$/) {
3934f2b10b24bab0049020d268382eda144e2aa064cTom Care      $BugDescription = $1;
3944f2b10b24bab0049020d268382eda144e2aa064cTom Care    }
3955744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3965744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3975744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
398ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  
399ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  if (!defined $BugCategory) {
400ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    $BugCategory = "Other";
401ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  }
4024f2b10b24bab0049020d268382eda144e2aa064cTom Care
4034f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Don't add internal statistics to the bug reports
4044f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($BugCategory =~ /statistics/i) {
4054f2b10b24bab0049020d268382eda144e2aa064cTom Care    AddStatLine($BugDescription, $Stats);
4064f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
4074f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
4084f2b10b24bab0049020d268382eda144e2aa064cTom Care  
409a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek  push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
41081983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek                 $BugPathLength ];
41122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
41222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
41322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
4143ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek# CopyFiles - Copy resource files to target directory.
41522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
41622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
4173ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremeneksub CopyFiles {
41822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
41922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
420e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek
421e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $JS = Cwd::realpath("$RealBin/sorttable.js");
42222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
42323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
424e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $JS);  
42522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
426e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $JS, "$Dir");
42722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
42823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
42922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
4303ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek    
431e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $CSS = Cwd::realpath("$RealBin/scanview.css");
432e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
4333ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Cannot find 'scanview.css'.\n")
434e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4353ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
436e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $CSS, "$Dir");
4373ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
4383ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
439e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4405744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
4415744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
4425744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
4434f2b10b24bab0049020d268382eda144e2aa064cTom Care# CalcStats - Calculates visitation statistics and returns the string.
4444f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4454f2b10b24bab0049020d268382eda144e2aa064cTom Care
4464f2b10b24bab0049020d268382eda144e2aa064cTom Caresub CalcStats {
4474f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
4484f2b10b24bab0049020d268382eda144e2aa064cTom Care
4494f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalBlocks = 0;
4504f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $UnreachedBlocks = 0;
4514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFunctions = scalar(@$Stats);
4524f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BlockAborted = 0;
4534f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $WorkListAborted = 0;
4544f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Aborted = 0;
4554f2b10b24bab0049020d268382eda144e2aa064cTom Care
4564f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculate the unique files
4574f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $FilesHash = {};
4584f2b10b24bab0049020d268382eda144e2aa064cTom Care
4594f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $Row (@$Stats) {
4604f2b10b24bab0049020d268382eda144e2aa064cTom Care    $FilesHash->{$Row->{Filename}} = 1;
4614f2b10b24bab0049020d268382eda144e2aa064cTom Care    $TotalBlocks += $Row->{Total};
4624f2b10b24bab0049020d268382eda144e2aa064cTom Care    $UnreachedBlocks += $Row->{Unreachable};
4634f2b10b24bab0049020d268382eda144e2aa064cTom Care    $BlockAborted++ if $Row->{Aborted} eq 'yes';
4644f2b10b24bab0049020d268382eda144e2aa064cTom Care    $WorkListAborted++ if $Row->{Empty} eq 'no';
4654f2b10b24bab0049020d268382eda144e2aa064cTom Care    $Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
4664f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
4674f2b10b24bab0049020d268382eda144e2aa064cTom Care
4684f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFiles = scalar(keys(%$FilesHash));
4694f2b10b24bab0049020d268382eda144e2aa064cTom Care
4704f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculations
4714f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
4724f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
4734f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4744f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
4754f2b10b24bab0049020d268382eda144e2aa064cTom Care      $TotalFunctions * 100);
4764f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
4774f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4784f2b10b24bab0049020d268382eda144e2aa064cTom Care
4794f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
4804f2b10b24bab0049020d268382eda144e2aa064cTom Care    . " in $TotalFiles files\n"
4814f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$Aborted functions aborted early ($PercentAborted%)\n"
4824f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
4834f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
4844f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
4854f2b10b24bab0049020d268382eda144e2aa064cTom Care
4864f2b10b24bab0049020d268382eda144e2aa064cTom Care  return $StatsString;
4874f2b10b24bab0049020d268382eda144e2aa064cTom Care}
4884f2b10b24bab0049020d268382eda144e2aa064cTom Care
4894f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
4919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
4929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
493a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
4949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4954f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Dir           = shift;
4964f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BaseDir       = shift;
4974f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $AnalyzerStats = shift;
4989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
499fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
5009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
5019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
50223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
503363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
5049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
5059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
5069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
507938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @files = grep { /^report-.*\.html$/ } readdir(DIR);
5089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
5099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
510938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar(@files) == 0 and ! -e "$Dir/failures") {
51123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
51220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
513363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
5149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
5155744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
516991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  # Scan each report file and build an index.  
5174f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Index;
5184f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Stats;
5194f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
5205744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
521938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  # Scan the failures directory and use the information in the .info files
522d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # to update the common prefix directory.
523938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @failures;
524938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @attributes_ignored;
525938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (-d "$Dir/failures") {
526938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");
527938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
528d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    closedir(DIR);
529938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");        
530938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
531938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    closedir(DIR);
532938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    foreach my $file (@failures) {
533938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
534d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      my $Path = <IN>;
535d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      if (defined $Path) { UpdatePrefix($Path); }
536d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      close IN;
537d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    }    
538d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  }
539d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  
54063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
54163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
54263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
5435744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
5446e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
5456e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
5465744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
5475744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
5485744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
5497cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<title>${HtmlTitle}</title>
550f143545ce5ce125e7c1aa6fca9df372bfb604e9cTed Kremenek<link type="text/css" rel="stylesheet" href="scanview.css"/>
55122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
5526e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
5536e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
5546e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
5556e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
5566e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
5576e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
5586e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
5596e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
5606e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5616e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
562ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
5632350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenekfunction CopyCheckedStateToCheckButtons(SummaryCheckButton) {
5642350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  var Inputs = document.getElementsByTagName("input");
5652350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  for ( var i = 0 ; i < Inputs.length; ++i ) {
5662350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    if (Inputs[i].type == "checkbox") {
5672350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      if(Inputs[i] != SummaryCheckButton) {
5682350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].checked = SummaryCheckButton.checked;
5692350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].onclick();
5702350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek	  }
5712350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    }
5722350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  }
5732350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek}
5742350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek
575999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekfunction returnObjById( id ) {
576999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (document.getElementById) 
577999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.getElementById(id);
578999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.all)
579999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.all[id];
580999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.layers) 
581999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.layers[id];
582999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    return returnVar; 
583999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek}
584999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
585999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekvar NumUnchecked = 0;
586999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
5876e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
5886e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
5896e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
590999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (--NumUnchecked == 0) {
591999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek      returnObjById("AllBugsCheck").checked = true;
592999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    }
5936e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5946e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
5956e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
596999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    NumUnchecked++;
597999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    returnObjById("AllBugsCheck").checked = false;
5986e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5996e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
6006e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
6011d1abb1dec3d0b7609809d876a16a64a021e96e7Ted Kremenek<!-- SUMMARYENDHEAD -->
6026e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
6036e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
6047cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h1>${HtmlTitle}</h1>
6057cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6067cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<table>
6077cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
6087cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
6097cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
610b4882d50923881d1a01af4d5604b5baaa141cdf9Douglas Gregor<tr><th>Clang Version:</th><td>${ClangVersion}</td></tr>
6117cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Date:</th><td>${Date}</td></tr>
6127cba11262458df05951432b54997eb40a35dbf9eTed KremenekENDTEXT
6137cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6147cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
6157cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if (defined($BuildName) && defined($BuildDate));
6167cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
6177cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT <<ENDTEXT;
6187cba11262458df05951432b54997eb40a35dbf9eTed Kremenek</table>
6196e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6206e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
621991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files)) {
622991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Print out the summary table.
623991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my %Totals;
624ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
625991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( @Index ) {
626ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_type = ($row->[2]);
627ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_category = ($row->[1]);
628ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $key = "$bug_category:$bug_type";
629ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
630ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
631ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else { $Totals{$key}->[0]++; }
6326e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
633991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6347cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    print OUT "<h2>Bug Summary</h2>";
635991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
636991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $BuildName) {
637991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
6386e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
639f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
6402350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  my $TotalBugs = scalar(@Index);
6416e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
642ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table>
643ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
644999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed 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>
6456e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6466e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
647ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    my $last_category;
648ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
649ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $key (
650ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      sort {
651ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $x = $Totals{$a};
652ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $y = $Totals{$b};
653ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $res = $x->[1] cmp $y->[1];
654ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res = $x->[2] cmp $y->[2] if ($res == 0);
655ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res
656ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      } keys %Totals ) 
657ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    {
658ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $val = $Totals{$key};
659ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $category = $val->[1];
660ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $last_category or $last_category ne $category) {
661ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $last_category = $category;
662ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
663ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }      
664ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = lc $key;
665ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
666ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr><td class=\"SUMM_DESC\">";
667ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[2];
6682350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      print OUT "</td><td class=\"Q\">";
669ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[0];
670ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
671991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
6726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
6746e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6756e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
6766e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
6777cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h2>Reports</h2>
678ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
679ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table class="sortable" style="table-layout:automatic">
680ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr>
681ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td>Bug Group</td>
682ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
683bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
684ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="Q">Line</td>
68581983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek  <td class="Q">Path Length</td>
6862645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
687ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <!-- REPORTBUGCOL -->
688ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek</tr></thead>
689ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<tbody>
6905744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
6919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
692991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $prefix = GetPrefix();
693991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $regex;
694991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFileRegex;
695991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFilePrefix = "File:</td><td>";
6967a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
697991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $prefix) { 
698991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $regex = qr/^\Q$prefix\E/is;    
699991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
700991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }    
7017a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
702ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
703ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = "$row->[1]:$row->[2]";
704ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x = lc $x;
705ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
7066e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
707991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $ReportFile = $row->[0];
708ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          
709ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr class=\"bt_$x\">";
710ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
711991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT $row->[1];
712ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
713ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
714ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $row->[2];
715ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
716ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
717ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Update the file prefix.      
718ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $fname = $row->[3];
719ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
720991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (defined $regex) {
721991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $fname =~ s/$regex//;
722991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
723991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
724ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
72591639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      print OUT "<td>";      
726ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my @fname = split /\//,$fname;
727ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if ($#fname > 0) {
728ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        while ($#fname >= 0) {
729ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          my $x = shift @fname;
730ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          print OUT $x;
731ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          if ($#fname >= 0) {
732ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek            print OUT "<span class=\"W\"> </span>/";
733ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          }
734ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        }
735ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
736ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else {
737ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT $fname;
73891639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      }      
739ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
740ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
741ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Print out the quantities.
74281983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for my $j ( 4 .. 5 ) {
743ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td class=\"Q\">$row->[$j]</td>";        
744ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
745ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
746991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Print the rest of the columns.
74781983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for (my $j = 6; $j <= $#{$row}; ++$j) {
748ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td>$row->[$j]</td>"
749991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
7507f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
751991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Emit the "View" link.
75268005ddb49b88c2f6cdd88185d72d8b411d2dbc9Ted Kremenek      print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
7533cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
754e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar      # Emit REPORTBUG markers.
755ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
756e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar        
757991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # End the row.
758991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</tr>\n";
759991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
760991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
761ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    print OUT "</tbody>\n</table>\n\n";
762991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  }
763991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
764938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar (@failures) || scalar(@attributes_ignored)) {
765938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    print OUT "<h2>Analyzer Failures</h2>\n";
766938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
767938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @attributes_ignored) {
768938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "The analyzer's parser ignored the following attributes:<p>\n";
769938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
770938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
771938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @attributes_ignored) {
772938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
773938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $attribute = $1;
774938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the attribute file to get the first file that failed.
775938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (!open (ATTR, "$Dir/failures/$file"));
776938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile = <ATTR>;
777938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $ppfile;
778938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close ATTR;
779938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (! -e "$Dir/failures/$ppfile");
780938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the info file and get the name of the source file.
781938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$ppfile.info.txt") or
782938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$ppfile.info.txt\n";
783938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $srcfile = <INFO>;
784938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $srcfile;
785938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close (INFO);
786938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Print the information in the table.
787938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $prefix = GetPrefix();
788938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
789938eef139ad43345248235da31f78a759dd18f13Ted 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";
790938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile_clang = $ppfile;
791938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
792938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
793938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      }
794938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
795938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }
796938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
797938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @failures) {
798938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<p>The analyzer had problems processing the following files:</p>\n";
799938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
800938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
801938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @failures) {
80282a1253077cd0832e4d347062b911cd305ab62d1Ted Kremenek        $file =~ /(.+).info.txt$/;
803991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Get the preprocessed file.
804991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $ppfile = $1;
805991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Open the info file and get the name of the source file.
806938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$file") or
807938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$file\n";
808991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $srcfile = <INFO>;
8095d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $srcfile;
8105d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        my $problem = <INFO>;
8115d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $problem;
812991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        close (INFO);
813991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Print the information in the table.
814d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        my $prefix = GetPrefix();
8159f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
816938eef139ad43345248235da31f78a759dd18f13Ted 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";
817ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        my $ppfile_clang = $ppfile;
818ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
819938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
820991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
821938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
822938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }    
823e2c8663ad2b110712401145b866072bb94108058Nico 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";
8245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
8255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
826991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  print OUT "</body></html>\n";  
8275744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
8283ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  CopyFiles($Dir);
82920161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
83020161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
83120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
832fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
83320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
8344f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Print statistics
8354f2b10b24bab0049020d268382eda144e2aa064cTom Care  print CalcStats(\@Stats) if $AnalyzerStats;
8364f2b10b24bab0049020d268382eda144e2aa064cTom Care
83723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
838150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
839150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
8405950b3f93a6e8a6ae8bd59a0ef5797e9f88f0bc3Ted Kremenek    Diag("Run 'scan-view $Dir' to examine bug reports.\n");
841150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
842363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
843938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
844991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
845363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
8469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
849dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
850dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
851dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
8526b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
8536b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
8546b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
8556b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
8566b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8576b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
8586b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
8596b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
8606b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
8616b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
8626b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8636b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8646b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
8656b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
8666b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8676b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
8686b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
869dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremeneksub RunBuildCommand {
870dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
871dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
8727442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
873dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
8746195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
875524c308506e77e173092e87a0724a27817311428Ted Kremenek  my $CXXAnalyzer = shift;
876dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
8773301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
8783301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
8793301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
8803301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
8813301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
88292548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek  if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or 
88392548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?cc[^\/]*$)/ or
88492548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
88505acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek      $Cmd =~ /(.*\/?clang$)/ or 
88692548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
88792548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek
88892548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
88951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CC"} = $1;      
89092548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    }
89192548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek        
892dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
8936195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
894dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
89551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  elsif ($Cmd =~ /(.*\/?g\+\+[^\/]*$)/ or 
89651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+[^\/]*$)/ or
89751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?llvm-g\+\+[^\/]*$)/ or
89805acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek        $Cmd =~ /(.*\/?clang\+\+$)/ or
89951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+-analyzer[^\/]*$)/) {
90051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    if (!($Cmd =~ /c\+\+-analyzer/) and !defined $ENV{"CCC_CXX"}) {
90151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CXX"} = $1;      
90251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    }        
90351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    shift @$Args;
904524c308506e77e173092e87a0724a27817311428Ted Kremenek    unshift @$Args, $CXXAnalyzer;
90551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  }
9067442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
9077442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
9086fba85dc6509069ff7735283464bd02da2da6eebTed Kremenek      AddIfNotPresent($Args, "CC=$CCAnalyzer");
909524c308506e77e173092e87a0724a27817311428Ted Kremenek      AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
9106b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
9118912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
9127442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
9137442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    elsif ($Cmd eq "xcodebuild") {
9146b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
9157442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
9166b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
9176b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
9186b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($Cmd eq "xcodebuild") {
91987752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    # Check if using iPhone SDK 3.0 (simulator).  If so the compiler being
92087752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    # used should be gcc-4.2.
92187752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    if (!defined $ENV{"CCC_CC"}) {
92287752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek      for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
92387752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek        if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
92487752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek          if (@$Args[$i+1] =~ /^iphonesimulator3/) {
92587752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek            $ENV{"CCC_CC"} = "gcc-4.2";
92651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek            $ENV{"CCC_CXX"} = "g++-4.2";            
92787752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek          }
92887752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek        }
92987752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek      }
93087752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    }
93187752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek
932cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable PCH files until clang supports them.
933cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
934915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    
935915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
936915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
937524c308506e77e173092e87a0724a27817311428Ted Kremenek    # (via c++-analyzer) when linking such files.
938524c308506e77e173092e87a0724a27817311428Ted Kremenek    $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
9396b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
940dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
9415a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
942dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
943dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
944dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
9459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
9469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
9479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
948a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
9499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
9505744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
951a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
9522b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
953f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
954f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
955fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
956f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
957f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
958f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
959f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
9602b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
9612b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
962e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek -analyze-headers - Also analyze functions in #included files.
9638382cf57b722f130f1a6b45380639871c07271c1Ted Kremenek 
964363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -o             - Target directory for HTML report files.  Subdirectories
965a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop                  will be created as needed to represent separate "runs" of
9662b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  the analyzer.  If this option is not specified, a directory
967ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek                  is created in /tmp (TMPDIR on Mac OS X) to store the reports.
968db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek                  
969363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -h             - Display this message.
970363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
9711262fc4d66584224234691d30d779f8ff004585cTed Kremenek
972363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -k             - Add a "keep on going" option to the specified build command.
973363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --keep-going     This option currently supports make and xcodebuild.
974f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  This is a convenience option; one can specify this
975f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  behavior directly using build options.
9762b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
9777cba11262458df05951432b54997eb40a35dbf9eTed Kremenek --html-title [title]       - Specify the title used on generated HTML pages.
9787cba11262458df05951432b54997eb40a35dbf9eTed Kremenek --html-title=[title]         If not specified, a default title will be used.
9797cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
980db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek -plist         - By default the output of scan-build is a set of HTML files.
981db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek                  This option outputs the results as a set of .plist files.
9822c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
9832c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks -plist-html    - By default the output of scan-build is a set of HTML files.
9842c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks                  This option outputs the results as a set of HTML 
9852c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks                  and .plist files.
9862c3038edc2a691b2462ef4bc7fae8f4c9a494154Anna Zaks 
987363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --status-bugs  - By default, the exit status of $Prog is the same as the
988363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  executed build command.  Specifying this option causes the
989363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  exit status of $Prog to be 1 if it found potential bugs
990363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  and 0 otherwise.
9912b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
992a772b86a6edaf9f110bf7d3e6c8201723371bc9aAnna Zaks --use-cc [compiler path]   - $Prog attempts to guess the default compiler for
993386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc=[compiler path]     your C and Objective-C code. Use this option
994386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
995386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
996a772b86a6edaf9f110bf7d3e6c8201723371bc9aAnna Zaks --use-c++ [compiler path]  - $Prog attempts to guess the default compiler for
997386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++=[compiler path]    your C++ and Objective-C++ code. Use this option
998386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
999f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
1000363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -v             - Verbose output from $Prog and the analyzer.
1001386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                  A second and third '-v' increases verbosity.
1002363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
1003363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -V             - View analysis results in a web browser when the build
1004363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --view           completes.
10057f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
1006be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed KremenekADVANCED OPTIONS:
1007be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
10089f4ecb34d502f6aad7d635dd3aec24a373ef5c9bTed Kremenek -constraints [model] - Specify the contraint engine used by the analyzer.
10099f4ecb34d502f6aad7d635dd3aec24a373ef5c9bTed Kremenek                        By default the 'range' model is used.  Specifying 
10109f4ecb34d502f6aad7d635dd3aec24a373ef5c9bTed Kremenek                        'basic' uses a simpler, less powerful constraint model
1011d4c7684f19703d75b989364da80727d635f99b53Ted Kremenek                        used by checker-0.160 and earlier.
1012be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
1013be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek -store [model] - Specify the store model used by the analyzer. By default,
1014b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  the 'region' store model is used. 'region' specifies a field-
1015b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  sensitive store model. Users can also specify 'basic', which
1016b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  is far less precise but can more quickly analyze code.
1017b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  'basic' was the default store model for checker-0.221 and
1018b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  earlier.
1019b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek
1020e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek -no-failure-reports - Do not create a 'failures' subdirectory that includes
1021e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek                       analyzer crash reports and preprocessed source files.
1022b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
10234f2b10b24bab0049020d268382eda144e2aa064cTom Care -stats - Generates visitation statistics for the project being analyzed.
10244f2b10b24bab0049020d268382eda144e2aa064cTom Care
10254f2b10b24bab0049020d268382eda144e2aa064cTom Care -maxloop N - specifiy the number of times a block can be visited before giving
102609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek              up. Default is 4. Increase for more comprehensive coverage at a
10274f2b10b24bab0049020d268382eda144e2aa064cTom Care              cost of speed.
102809fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
102909fbf297da918760ce33302a3f709a77f43af265Ted KremenekCONTROLLING CHECKERS:
103009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
103109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek A default group of checkers are always run unless explicitly disabled.
103209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek Checkers may be enabled/disabled using the following options:
103309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek
103409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -enable-checker [checker name]
103509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek -disable-checker [checker name]
1036f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks 
1037f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna ZaksLOADING CHECKERS:
1038f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1039f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks Loading external checkers using the clang plugin interface:
1040f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1041f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks -load-plugin [plugin library]
1042d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
1043b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1044ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for list of checkers that are enabled.
1045f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
1046f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# create a list to load the plugins via the 'Xclang' command line
1047f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks# argument
1048f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksmy @PluginLoadCommandline_xclang;
1049f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaksforeach my $param ( @PluginsToLoad ) {
1050f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, "-Xclang" );
1051f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  push ( @PluginLoadCommandline_xclang, $param );
1052f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks}
1053ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy %EnabledCheckers;
1054ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekforeach my $lang ("c", "objective-c", "objective-c++", "c++") {
1055ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  pipe(FROM_CHILD, TO_PARENT);
1056ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $pid = fork();
1057ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if ($pid == 0) {
1058ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    close FROM_CHILD;
1059ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDOUT,">&", \*TO_PARENT);
1060ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDERR,">&", \*TO_PARENT);
1061f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###'); 
1062ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1063ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(TO_PARENT);
1064ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1065ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    foreach my $val (split /\s+/) {
1066ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $val =~ s/\"//g;
1067ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($val =~ /-analyzer-checker\=([^\s]+)/) {
1068ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $EnabledCheckers{$1} = 1;
1069ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1070ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1071ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1072ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  waitpid($pid,0);
1073ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(FROM_CHILD);
1074ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1075ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1076ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for complete list of checkers.
1077ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekpipe(FROM_CHILD, TO_PARENT);
1078ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $pid = fork();
1079ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif ($pid == 0) {
1080ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close FROM_CHILD;
1081ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  open(STDOUT,">&", \*TO_PARENT);
1082ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  open(STDERR,">&", \*TO_PARENT);
1083f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
1084ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1085ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekclose(TO_PARENT);
1086ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $foundCheckers = 0;
1087ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekwhile(<FROM_CHILD>) {
1088ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if (/CHECKERS:/) {
1089ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $foundCheckers = 1;
1090ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    last;
1091ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1092ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1093ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!$foundCheckers) {
1094ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  print "  *** Could not query Clang for the list of available checkers.";
1095ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1096ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekelse {
1097ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  print("\nAVAILABLE CHECKERS:\n\n");
1098ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $skip = 0;
1099ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
11004cd6ea9989989e9f3a87b22c794ce76c6899d0a1Ted Kremenek    if (/experimental/) {
1101ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $skip = 1;
1102ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      next;
1103ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1104ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    if ($skip) {
1105ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      next if (!/^\s\s[^\s]/);
1106ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $skip = 0;
1107ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1108ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    s/^\s\s//;
1109ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    if (/^([^\s]+)/) {
1110ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      # Is the checker enabled?
1111ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $checker = $1;
1112ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $enabled = 0;
1113ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $aggregate = "";
1114ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      foreach my $domain (split /\./, $checker) {
1115ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $aggregate .= $domain;
1116ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        if ($EnabledCheckers{$aggregate}) {
1117ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek          $enabled =1;
1118ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek          last;
1119f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks        }
1120f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks        # append a dot, if an additional domain is added in the next iteration
1121f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks        $aggregate .= ".";
1122ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1123ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      
1124ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($enabled) {
1125ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print " + ";
1126ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1127ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      else {
1128ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print "   ";
1129ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1130ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1131ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    else {
1132ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      print "   ";
1133ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1134ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    print $_;
1135ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  } 
1136ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1137ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekwaitpid($pid,0);
1138ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekclose(FROM_CHILD);
11397fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1140b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
1141b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1142ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek NOTE: "+" indicates that an analysis is enabled by default.
1143b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
11442b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
11452b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1146363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
114739eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
11485744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
11492b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1150363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek $Prog -o /tmp/myhtmldir make -j4
11512b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
1152363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The above example causes analysis reports to be deposited into
1153363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
1154363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek A different subdirectory is created each time $Prog analyzes a project.
1155363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The analyzer should support most parallel builds, but not distributed builds.
11562b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
11572b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
11589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
11599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
11609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
11617cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# HtmlEscape - HTML entity encode characters that are special in HTML
11627cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11637cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11647cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub HtmlEscape {
11657cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
11667cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
11677cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $tmp = $arg;
116887f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/&/&amp;/g;
116987f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/</&lt;/g;
117087f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/>/&gt;/g;
11717cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  return $tmp;
11727cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
11737cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11747cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11757cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# ShellEscape - backslash escape characters that are special to the shell
11767cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11777cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11787cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub ShellEscape {
11797cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
11807cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
118187f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
118287f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  return $arg;
11837cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
11847cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11857cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
11879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
11889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1189e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekmy $AnalyzeHeaders = 0;
11909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
11919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
11927f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
1193363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
1194b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
119507c3767be59472e19183c7b51fae76481465cb51Zhongxing Xumy $StoreModel;
1196be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekmy $ConstraintsModel;
11978d8bc9157fccab6a4089c41cdad9e12045edd736Ted Kremenekmy $OutputFormat = "html";
11984f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $AnalyzerStats = 0;
11994f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $MaxLoop = 0;
12009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
12029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1203a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
12049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
12059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1206ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1207ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $displayHelp = 0;
1208ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
12099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
12109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
12129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
12149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
12152f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
1216ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $displayHelp = 1;
1217ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    shift @ARGV;
1218ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    next;
12199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1221e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  if ($arg eq '-analyze-headers') {
1222e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    shift @ARGV;    
1223e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    $AnalyzeHeaders = 1;
1224e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    next;
1225e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  }
1226e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
12279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
12289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
12299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
12309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
123123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
12329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
12339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1234db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # Construct an absolute path.  Uses the current working directory
1235db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # as a base if the original path was not absolute.
1236db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    $HtmlDir = abs_path(shift @ARGV);
1237db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    
12389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
12399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12407cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12417cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--html-title(=(.+))?$/) {
12427cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    shift @ARGV;
12437cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1244278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq '') {
12457cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      if (!@ARGV) {
12467cba11262458df05951432b54997eb40a35dbf9eTed Kremenek        DieDiag("'--html-title' option requires a string.\n");
12477cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      }
12487cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12497cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = shift @ARGV;
12507cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    } else {
12517cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = $2;
12527cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    }
12537cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12547cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    next;
12557cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  }
12569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12572b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
12589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
12599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
12609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
12619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12627fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1263f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
1264f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
1265f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
1266f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1267278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1268f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
1269f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
1270f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
1271f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
1272f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1273f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
1274f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
1275f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1276f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1277f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
1278f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
1279f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
1280f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
12817cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
1282386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
128351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    my $cxx;    
1284386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
1285278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1286386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
1287386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
1288386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
128951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = shift @ARGV;
1290386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
1291386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
129251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = $2;
1293386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
129451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    
129551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    $ENV{"CCC_CXX"} = $cxx;
1296386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
1297386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
1298386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
12999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
13009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
13019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
13029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
13039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
13049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
13057f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
13067f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
13077f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
13087f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
13097f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
13107f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
1311363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
1312363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
1313363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
1314363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
1315363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
131607c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu
131707c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  if ($arg eq "-store") {
131807c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    shift @ARGV;
1319be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $StoreModel = shift @ARGV;
1320be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    next;
1321be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  }
1322be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  
1323be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  if ($arg eq "-constraints") {
1324be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    shift @ARGV;
1325be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $ConstraintsModel = shift @ARGV;
132607c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    next;
132707c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  }
1328363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
1329db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  if ($arg eq "-plist") {
1330db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    shift @ARGV;
1331db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    $OutputFormat = "plist";
1332db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    next;
1333db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
13347753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  if ($arg eq "-plist-html") {
13357753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    shift @ARGV;
13367753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    $OutputFormat = "plist-html";
13377753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    next;
13387753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  }
1339e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  
1340e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  if ($arg eq "-no-failure-reports") {
1341e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    $ENV{"CCC_REPORT_FAILURES"} = 0;
1342e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    next;
1343e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  }
13444f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-stats") {
13454f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
13464f2b10b24bab0049020d268382eda144e2aa064cTom Care    $AnalyzerStats = 1;
13474f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
13484f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
13494f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-maxloop") {
13504f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
13514f2b10b24bab0049020d268382eda144e2aa064cTom Care    $MaxLoop = shift @ARGV;
13524f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
13534f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
135409fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-enable-checker") {
135509fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
135609fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-checker", shift @ARGV;
135709fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
135809fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
135909fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  if ($arg eq "-disable-checker") {
136009fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    shift @ARGV;
136109fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV;
136209fbf297da918760ce33302a3f709a77f43af265Ted Kremenek    next;
136309fbf297da918760ce33302a3f709a77f43af265Ted Kremenek  }
1364f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  if ($arg eq "-load-plugin") {
1365f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    shift @ARGV;
1366f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    push @PluginsToLoad, "-load", shift @ARGV;
1367f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks    next;
1368f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  }
1369f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks  
137023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
13710062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
13729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
13739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
13749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1375ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!@ARGV and $displayHelp == 0) {
137623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
1377ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  $displayHelp = 1;
1378ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1379ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1380ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif ($displayHelp) {
13819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1382a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
13839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
13849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1385ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine where results go.
13867cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
13877cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
13887cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  unless (defined($HtmlTitle));
1389386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
13909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
1391684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
1392a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
13939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1394ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine the location of ccc-analyzer.
139551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $AbsRealBin = Cwd::realpath($RealBin);
139651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $Cmd = "$AbsRealBin/libexec/ccc-analyzer";
139751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $CmdCXX = "$AbsRealBin/libexec/c++-analyzer";
139851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek
1399ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenekif (!defined $Cmd || ! -x $Cmd) {
140051365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $Cmd = "$AbsRealBin/ccc-analyzer";
14016b89636db873142f562cf576df9bc195c5b8674bTed Kremenek  DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
1402ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenek}
140351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekif (!defined $CmdCXX || ! -x $CmdCXX) {
140451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $CmdCXX = "$AbsRealBin/c++-analyzer";
140551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
140651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek}
1407f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
1408fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenekif (!defined $ClangSB || ! -x $ClangSB) {
1409fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek  Diag("'clang' executable not found in '$RealBin/bin'.\n");
14106492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  Diag("Using 'clang' from path: $Clang\n");
1411fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek}
14120b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
1413ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Set the appropriate environment variables.
1414ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted KremenekSetHtmlEnv(\@ARGV, $HtmlDir);
14154f4b17da43d3be87a248e1e10bf0b7d8b5891efdTed Kremenek$ENV{'CC'} = $Cmd;
141651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek$ENV{'CXX'} = $CmdCXX;
1417f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek$ENV{'CLANG'} = $Clang;
141851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek$ENV{'CLANG_CXX'} = $ClangCXX;
14199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif ($Verbose >= 2) {
14209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
14219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1422a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenekif ($Verbose >= 3) {
1423a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek  $ENV{'CCC_ANALYZER_LOG'} = 1;
1424a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek}
1425e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekif ($AnalyzeHeaders) {
1426e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  push @AnalysesToRun,"-analyzer-opt-analyze-headers";  
1427e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek}
14284f2b10b24bab0049020d268382eda144e2aa064cTom Careif ($AnalyzerStats) {
1429251c27b6299a841d97901a014d02e4a62f1b6e8eTed Kremenek  push @AnalysesToRun, '-analyzer-checker', 'debug.Stats';
14304f2b10b24bab0049020d268382eda144e2aa064cTom Care}
14314f2b10b24bab0049020d268382eda144e2aa064cTom Careif ($MaxLoop > 0) {
14324f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop;
14334f2b10b24bab0049020d268382eda144e2aa064cTom Care}
14344f2b10b24bab0049020d268382eda144e2aa064cTom Care
14359012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
14369012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek
1437f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks$ENV{'CCC_ANALYZER_PLUGINS'} = join ' ',@PluginsToLoad;
1438f8e8a3eeff891d1c056c96b6d6be404533741ba7Anna Zaks
14393cab2b1c3798f2a6aa3526875801a02aebf6fc1dZhongxing Xuif (defined $StoreModel) {
144007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  $ENV{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
144107c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu}
1442be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekif (defined $ConstraintsModel) {
1443be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
1444be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek}
1445db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenekif (defined $OutputFormat) {
1446db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
1447db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek}
1448db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
14499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
1450524c308506e77e173092e87a0724a27817311428Ted Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX);
14519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
14527753b352366778d01c5cda4117356f181d3dd468Ted Kremenekif (defined $OutputFormat) {
14531182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  if ($OutputFormat =~ /plist/) {
14541182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis run complete.\n";
14551182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
14561182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  }
14571182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  elsif ($OutputFormat =~ /html/) {
14587753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    # Postprocess the HTML directory.
14594f2b10b24bab0049020d268382eda144e2aa064cTom Care    my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
14607753b352366778d01c5cda4117356f181d3dd468Ted Kremenek
14617753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ViewResults and -r "$HtmlDir/index.html") {
14627753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Analysis run complete.\n";
14637753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
14647753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      my $ScanView = Cwd::realpath("$RealBin/scan-view");
14657753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      if (! -x $ScanView) { $ScanView = "scan-view"; }
14667753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exec $ScanView, "$HtmlDir";
14677753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1468db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
14697753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ExitStatusFoundBugs) {
14707753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 1 if ($NumBugs > 0);
14717753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 0;
14727753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1473db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
1474363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
1475363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
14765656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
14775656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
1478