#!/usr/bin/env perl
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
#
# A script designed to wrap a build so that all calls to gcc are intercepted
# and piped to the static analyzer.
#
##===----------------------------------------------------------------------===##
use strict;
use warnings;
use FindBin qw($RealBin);
use Digest::MD5;
use File::Basename;
use Term::ANSIColor;
use Term::ANSIColor qw(:constants);
my $Verbose = 0; # Verbose output from this script.
my $Prog = "scan-build";
my $BuildName;
my $BuildDate;
my $CXX; # Leave undefined initially.
my $TERM = $ENV{'TERM'};
my $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
and defined $ENV{'SCAN_BUILD_COLOR'});
##----------------------------------------------------------------------------##
# Diagnostics
##----------------------------------------------------------------------------##
sub Diag {
if ($UseColor) {
print BOLD, MAGENTA "$Prog: @_";
print RESET;
}
else {
print "$Prog: @_";
}
}
sub DiagCrashes {
my $Dir = shift;
Diag ("The analyzer crashed on some source files.\n");
Diag ("Preprocessed versions of crashed files were deposited in '$Dir/crashes'.\n");
Diag ("Please consider submitting a bug report using these files:\n");
Diag (" http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
}
sub DieDiag {
if ($UseColor) {
print BOLD, RED "$Prog: ";
print RESET, RED @_;
print RESET;
}
else {
print "$Prog: ", @_;
}
exit(0);
}
##----------------------------------------------------------------------------##
# Some initial preprocessing of Clang options.
##----------------------------------------------------------------------------##
my $ClangSB = "$RealBin/clang";
my $Clang = $ClangSB;
if (! -x $ClangSB) {
$Clang = "clang";
}
my %AvailableAnalyses;
# Query clang for analysis options.
open(PIPE, "-|", $Clang, "--help") or
DieDiag("Cannot execute '$Clang'");
my $FoundAnalysis = 0;
while(<PIPE>) {
if ($FoundAnalysis == 0) {
if (/Available Source Code Analyses/) {
$FoundAnalysis = 1;
}
next;
}
if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
next if ($1 =~ /-dump/ or $1 =~ /-view/
or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
$AvailableAnalyses{$1} = $2;
next;
}
last;
}
close (PIPE);
my %AnalysesDefaultEnabled = (
'-warn-dead-stores' => 1,
'-checker-cfref' => 1,
'-warn-objc-methodsigs' => 1,
'-warn-objc-missing-dealloc' => 1,
'-warn-objc-unused-ivars' => 1
);
##----------------------------------------------------------------------------##
# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
##----------------------------------------------------------------------------##
sub GetHTMLRunDir {
die "Not enough arguments." if (@_ == 0);
my $Dir = shift @_;
my $TmpMode = 0;
if (!defined $Dir) {
$Dir = "/tmp";
$TmpMode = 1;
}
# Get current date and time.
my @CurrentTime = localtime();
my $year = $CurrentTime[5] + 1900;
my $day = $CurrentTime[3];
my $month = $CurrentTime[4] + 1;
my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
# Determine the run number.
my $RunNumber;
if (-d $Dir) {
if (! -r $Dir) {
DieDiag("directory '$Dir' exists but is not readable.\n");
}
# Iterate over all files in the specified directory.
my $max = 0;
opendir(DIR, $Dir);
my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
closedir(DIR);
foreach my $f (@FILES) {
# Strip the prefix '$Prog-' if we are dumping files to /tmp.
if ($TmpMode) {
next if (!($f =~ /^$Prog-(.+)/));
$f = $1;
}
my @x = split/-/, $f;
next if (scalar(@x) != 4);
next if ($x[0] != $year);
next if ($x[1] != $month);
next if ($x[2] != $day);
if ($x[3] > $max) {
$max