diff options
Diffstat (limited to 'tools/scan-build')
-rw-r--r-- | tools/scan-build/CMakeLists.txt | 82 | ||||
-rw-r--r-- | tools/scan-build/Makefile | 53 | ||||
-rwxr-xr-x | tools/scan-build/bin/scan-build (renamed from tools/scan-build/scan-build) | 743 | ||||
-rw-r--r-- | tools/scan-build/bin/scan-build.bat (renamed from tools/scan-build/scan-build.bat) | 0 | ||||
-rwxr-xr-x | tools/scan-build/bin/set-xcode-analyzer (renamed from tools/scan-build/set-xcode-analyzer) | 0 | ||||
-rwxr-xr-x | tools/scan-build/libexec/c++-analyzer (renamed from tools/scan-build/c++-analyzer) | 0 | ||||
-rw-r--r-- | tools/scan-build/libexec/c++-analyzer.bat (renamed from tools/scan-build/c++-analyzer.bat) | 0 | ||||
-rwxr-xr-x | tools/scan-build/libexec/ccc-analyzer (renamed from tools/scan-build/ccc-analyzer) | 20 | ||||
-rw-r--r-- | tools/scan-build/libexec/ccc-analyzer.bat (renamed from tools/scan-build/ccc-analyzer.bat) | 0 | ||||
-rw-r--r-- | tools/scan-build/man/scan-build.1 (renamed from tools/scan-build/scan-build.1) | 2 | ||||
-rw-r--r-- | tools/scan-build/share/scan-build/scanview.css (renamed from tools/scan-build/scanview.css) | 0 | ||||
-rw-r--r-- | tools/scan-build/share/scan-build/sorttable.js (renamed from tools/scan-build/sorttable.js) | 0 |
12 files changed, 579 insertions, 321 deletions
diff --git a/tools/scan-build/CMakeLists.txt b/tools/scan-build/CMakeLists.txt new file mode 100644 index 0000000..78c243d --- /dev/null +++ b/tools/scan-build/CMakeLists.txt @@ -0,0 +1,82 @@ +option(CLANG_INSTALL_SCANBUILD "Install the scan-build tool" ON) + +include(GNUInstallDirs) + +if (WIN32 AND NOT CYGWIN) + set(BinFiles + scan-build.bat) + set(LibexecFiles + ccc-analyzer.bat + c++-analyzer.bat) +else() + set(BinFiles + scan-build) + set(LibexecFiles + ccc-analyzer + c++-analyzer) + if (APPLE) + list(APPEND BinFiles + set-xcode-analyzer) + endif() +endif() + +set(ManPages + scan-build.1) + +set(ShareFiles + scanview.css + sorttable.js) + + +if(CLANG_INSTALL_SCANBUILD) + foreach(BinFile ${BinFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile} + ${CMAKE_BINARY_DIR}/bin/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile}) + install(PROGRAMS bin/${BinFile} DESTINATION bin) + endforeach() + + foreach(LibexecFile ${LibexecFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/libexec/${LibexecFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/libexec + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile} + ${CMAKE_BINARY_DIR}/libexec/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${LibexecFile}) + install(PROGRAMS libexec/${LibexecFile} DESTINATION libexec) + endforeach() + + foreach(ManPage ${ManPages}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1 + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage} + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage}) + install(PROGRAMS man/${ManPage} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + endforeach() + + foreach(ShareFile ${ShareFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/share/scan-build + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile} + ${CMAKE_BINARY_DIR}/share/scan-build/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile}) + install(FILES share/scan-build/${ShareFile} DESTINATION share/scan-build) + endforeach() + + add_custom_target(scan-build ALL DEPENDS ${Depends}) + set_target_properties(scan-build PROPERTIES FOLDER "Misc") +endif() diff --git a/tools/scan-build/Makefile b/tools/scan-build/Makefile new file mode 100644 index 0000000..23aa198 --- /dev/null +++ b/tools/scan-build/Makefile @@ -0,0 +1,53 @@ +##===- tools/scan-build/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. + +include $(CLANG_LEVEL)/../../Makefile.config +include $(CLANG_LEVEL)/Makefile + +ifeq ($(HOST_OS),MingW) + Suffix := .bat +endif + +CLANG_INSTALL_SCANBUILD ?= 1 + +ifeq ($(CLANG_INSTALL_SCANBUILD), 1) + InstallTargets := $(ToolDir)/scan-build$(Suffix) \ + $(LibexecDir)/c++-analyzer$(Suffix) \ + $(LibexecDir)/ccc-analyzer$(Suffix) \ + $(ShareDir)/scan-build/scanview.css \ + $(ShareDir)/scan-build/sorttable.js \ + $(ShareDir)/man/man1/scan-build.1 + + ifeq ($(HOST_OS),Darwin) + InstallTargets := $(InstallTargets) $(ToolDir)/set-xcode-analyzer + endif +endif + +all:: $(InstallTargets) + +$(ToolDir)/%: bin/% Makefile $(ToolDir)/.dir + $(Echo) "Copying $(notdir $<) to the 'bin' directory..." + $(Verb)cp $< $@ + $(Verb)chmod +x $@ + +$(LibexecDir)/%: libexec/% Makefile $(LibexecDir)/.dir + $(Echo) "Copying $(notdir $<) to the 'libexec' directory..." + $(Verb)cp $< $@ + $(Verb)chmod +x $@ + +$(ShareDir)/man/man1/%: man/% Makefile $(ShareDir)/man/man1/.dir + $(Echo) "Copying $(notdir $<) to the 'man' directory..." + $(Verb)cp $< $@ + +$(ShareDir)/scan-build/%: share/scan-build/% Makefile $(ShareDir)/scan-build/.dir + $(Echo) "Copying $(notdir $<) to the 'share' directory..." + $(Verb)cp $< $@ + diff --git a/tools/scan-build/scan-build b/tools/scan-build/bin/scan-build index d7cadc3..6a14484 100755 --- a/tools/scan-build/scan-build +++ b/tools/scan-build/bin/scan-build @@ -24,8 +24,8 @@ use Term::ANSIColor; use Term::ANSIColor qw(:constants); use Cwd qw/ getcwd abs_path /; use Sys::Hostname; +use Hash::Util qw(lock_keys); -my $Verbose = 0; # Verbose output from this script. my $Prog = "scan-build"; my $BuildName; my $BuildDate; @@ -39,15 +39,40 @@ my $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT my $UserName = HtmlEscape(getlogin() || getpwuid($<) || 'unknown'); my $HostName = HtmlEscape(hostname() || 'unknown'); my $CurrentDir = HtmlEscape(getcwd()); -my $CurrentDirSuffix = basename($CurrentDir); -my @PluginsToLoad; my $CmdArgs; -my $HtmlTitle; - my $Date = localtime(); +# Command-line/config arguments. +my %Options = ( + Verbose => 0, # Verbose output from this script. + AnalyzeHeaders => 0, + OutputDir => undef, # Parent directory to store HTML files. + HtmlTitle => basename($CurrentDir)." - scan-build results", + IgnoreErrors => 0, # Ignore build errors. + ViewResults => 0, # View results when the build terminates. + ExitStatusFoundBugs => 0, # Exit status reflects whether bugs were found + KeepEmpty => 0, # Don't remove output directory even with 0 results. + EnableCheckers => {}, + DisableCheckers => {}, + UseCC => undef, # C compiler to use for compilation. + UseCXX => undef, # C++ compiler to use for compilation. + AnalyzerTarget => undef, + StoreModel => undef, + ConstraintsModel => undef, + InternalStats => undef, + OutputFormat => "html", + ConfigOptions => [], # Options to pass through to the analyzer's -analyzer-config flag. + ReportFailures => undef, + AnalyzerStats => 0, + MaxLoop => 0, + PluginsToLoad => [], + AnalyzerDiscoveryMethod => undef, + OverrideCompiler => 0 # The flag corresponding to the --override-compiler command line option. +); +lock_keys(%Options); + ##----------------------------------------------------------------------------## # Diagnostics ##----------------------------------------------------------------------------## @@ -231,7 +256,7 @@ sub SetHtmlEnv { return; } - if ($Verbose) { + if ($Options{Verbose}) { Diag("Emitting reports for this run to '$Dir'.\n"); } @@ -437,7 +462,7 @@ sub CopyFiles { my $Dir = shift; - my $JS = Cwd::realpath("$RealBin/sorttable.js"); + my $JS = Cwd::realpath("$RealBin/../share/scan-build/sorttable.js"); DieDiag("Cannot find 'sorttable.js'.\n") if (! -r $JS); @@ -447,7 +472,7 @@ sub CopyFiles { DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n") if (! -r "$Dir/sorttable.js"); - my $CSS = Cwd::realpath("$RealBin/scanview.css"); + my $CSS = Cwd::realpath("$RealBin/../share/scan-build/scanview.css"); DieDiag("Cannot find 'scanview.css'.\n") if (! -r $CSS); @@ -582,7 +607,7 @@ sub Postprocess { print OUT <<ENDTEXT; <html> <head> -<title>${HtmlTitle}</title> +<title>${Options{HtmlTitle}}</title> <link type="text/css" rel="stylesheet" href="scanview.css"/> <script src="sorttable.js"></script> <script language='javascript' type="text/javascript"> @@ -637,7 +662,7 @@ function ToggleDisplay(CheckButton, ClassName) { <!-- SUMMARYENDHEAD --> </head> <body> -<h1>${HtmlTitle}</h1> +<h1>${Options{HtmlTitle}}</h1> <table> <tr><th>User:</th><td>${UserName}\@${HostName}</td></tr> @@ -912,21 +937,25 @@ sub AddIfNotPresent { } sub SetEnv { - my $Options = shift @_; - foreach my $opt ('CC', 'CXX', 'CLANG', 'CLANG_CXX', - 'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS', - 'CCC_ANALYZER_CONFIG') { - die "$opt is undefined\n" if (!defined $opt); - $ENV{$opt} = $Options->{$opt}; - } - foreach my $opt ('CCC_ANALYZER_STORE_MODEL', - 'CCC_ANALYZER_PLUGINS', - 'CCC_ANALYZER_INTERNAL_STATS', - 'CCC_ANALYZER_OUTPUT_FORMAT') { - my $x = $Options->{$opt}; - if (defined $x) { $ENV{$opt} = $x } - } - my $Verbose = $Options->{'VERBOSE'}; + my $EnvVars = shift @_; + foreach my $var ('CC', 'CXX', 'CLANG', 'CLANG_CXX', + 'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS', + 'CCC_ANALYZER_CONFIG') { + die "$var is undefined\n" if (!defined $var); + $ENV{$var} = $EnvVars->{$var}; + } + foreach my $var ('CCC_ANALYZER_STORE_MODEL', + 'CCC_ANALYZER_CONSTRAINTS_MODEL', + 'CCC_ANALYZER_INTERNAL_STATS', + 'CCC_ANALYZER_OUTPUT_FORMAT', + 'CCC_CC', + 'CCC_CXX', + 'CCC_REPORT_FAILURES', + 'CLANG_ANALYZER_TARGET') { + my $x = $EnvVars->{$var}; + if (defined $x) { $ENV{$var} = $x } + } + my $Verbose = $EnvVars->{'VERBOSE'}; if ($Verbose >= 2) { $ENV{'CCC_ANALYZER_VERBOSE'} = 1; } @@ -935,15 +964,12 @@ sub SetEnv { } } -# The flag corresponding to the --override-compiler command line option. -my $OverrideCompiler = 0; - sub RunXcodebuild { my $Args = shift; my $IgnoreErrors = shift; my $CCAnalyzer = shift; my $CXXAnalyzer = shift; - my $Options = shift; + my $EnvVars = shift; if ($IgnoreErrors) { AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES"); @@ -972,14 +998,14 @@ sub RunXcodebuild { # If --override-compiler is explicitely requested, resort to the old # behavior regardless of Xcode version. - if ($OverrideCompiler) { + if ($Options{OverrideCompiler}) { $oldBehavior = 1; } if ($oldBehavior == 0) { - my $OutputDir = $Options->{"OUTPUT_DIR"}; - my $CLANG = $Options->{"CLANG"}; - my $OtherFlags = $Options->{"CCC_ANALYZER_ANALYSIS"}; + my $OutputDir = $EnvVars->{"OUTPUT_DIR"}; + my $CLANG = $EnvVars->{"CLANG"}; + my $OtherFlags = $EnvVars->{"CCC_ANALYZER_ANALYSIS"}; push @$Args, "RUN_CLANG_STATIC_ANALYZER=YES", "CLANG_ANALYZER_OUTPUT=plist-html", @@ -991,7 +1017,7 @@ sub RunXcodebuild { } # Default to old behavior where we insert a bogus compiler. - SetEnv($Options); + SetEnv($EnvVars); # Check if using iPhone SDK 3.0 (simulator). If so the compiler being # used should be gcc-4.2. @@ -1023,14 +1049,14 @@ sub RunBuildCommand { my $Cmd = $Args->[0]; my $CCAnalyzer = shift; my $CXXAnalyzer = shift; - my $Options = shift; + my $EnvVars = shift; if ($Cmd =~ /\bxcodebuild$/) { - return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options); + return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $EnvVars); } # Setup the environment. - SetEnv($Options); + SetEnv($EnvVars); if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or $Cmd =~ /(.*\/?cc[^\/]*$)/ or @@ -1074,6 +1100,7 @@ sub RunBuildCommand { sub DisplayHelp { + my $ArgClangNotFoundErrMsg = shift; print <<ENDTEXT; USAGE: $Prog [options] <build command> [build options] @@ -1145,10 +1172,21 @@ OPTIONS: scan-build to use a specific compiler for *compilation* then you can use this option to specify a path to that compiler. + If the given compiler is a cross compiler, you may also need to provide + --analyzer-target option to properly analyze the source code because static + analyzer runs as if the code is compiled for the host machine by default. + --use-c++ [compiler path] --use-c++=[compiler path] - This is the same as "-use-cc" but for C++ code. + This is the same as "--use-cc" but for C++ code. + + --analyzer-target [target triple name for analysis] + --analyzer-target=[target triple name for analysis] + + This provides target triple information to clang static analyzer. + It only changes the target for analysis but doesn't change the target of a + real compiler given by --use-cc and --use-c++ options. -v @@ -1221,32 +1259,41 @@ LOADING CHECKERS: -load-plugin [plugin library] ENDTEXT - # Query clang for list of checkers that are enabled. + if (defined $Clang && -x $Clang) { + # Query clang for list of checkers that are enabled. + + # create a list to load the plugins via the 'Xclang' command line + # argument + my @PluginLoadCommandline_xclang; + foreach my $param ( @{$Options{PluginsToLoad}} ) { + push ( @PluginLoadCommandline_xclang, "-Xclang" ); + push ( @PluginLoadCommandline_xclang, "-load" ); + push ( @PluginLoadCommandline_xclang, "-Xclang" ); + push ( @PluginLoadCommandline_xclang, $param ); + } - # create a list to load the plugins via the 'Xclang' command line - # argument - my @PluginLoadCommandline_xclang; - foreach my $param ( @PluginsToLoad ) { - push ( @PluginLoadCommandline_xclang, "-Xclang" ); - push ( @PluginLoadCommandline_xclang, $param ); - } - my %EnabledCheckers; - foreach my $lang ("c", "objective-c", "objective-c++", "c++") { - my $ExecLine = join(' ', qq/"$Clang"/, @PluginLoadCommandline_xclang, "--analyze", "-x", $lang, "-", "-###", "2>&1", "|"); - open(PS, $ExecLine); - while (<PS>) { - foreach my $val (split /\s+/) { - $val =~ s/\"//g; - if ($val =~ /-analyzer-checker\=([^\s]+)/) { - $EnabledCheckers{$1} = 1; + my %EnabledCheckers; + foreach my $lang ("c", "objective-c", "objective-c++", "c++") { + my $ExecLine = join(' ', qq/"$Clang"/, @PluginLoadCommandline_xclang, "--analyze", "-x", $lang, "-", "-###", "2>&1", "|"); + open(PS, $ExecLine); + while (<PS>) { + foreach my $val (split /\s+/) { + $val =~ s/\"//g; + if ($val =~ /-analyzer-checker\=([^\s]+)/) { + $EnabledCheckers{$1} = 1; + } } } } - } - # Query clang for complete list of checkers. - if (defined $Clang && -x $Clang) { - my $ExecLine = join(' ', qq/"$Clang"/, "-cc1", @PluginsToLoad, "-analyzer-checker-help", "2>&1", "|"); + # Query clang for complete list of checkers. + my @PluginLoadCommandline; + foreach my $param ( @{$Options{PluginsToLoad}} ) { + push ( @PluginLoadCommandline, "-load" ); + push ( @PluginLoadCommandline, $param ); + } + + my $ExecLine = join(' ', qq/"$Clang"/, "-cc1", @PluginLoadCommandline, "-analyzer-checker-help", "2>&1", "|"); open(PS, $ExecLine); my $foundCheckers = 0; while (<PS>) { @@ -1302,6 +1349,12 @@ ENDTEXT } close PS; } + else { + print " *** Could not query Clang for the list of available checkers.\n"; + if (defined $ArgClangNotFoundErrMsg) { + print " *** Reason: $ArgClangNotFoundErrMsg\n"; + } + } print <<ENDTEXT @@ -1347,284 +1400,331 @@ sub ShellEscape { } ##----------------------------------------------------------------------------## +# FindClang - searches for 'clang' executable. +##----------------------------------------------------------------------------## + +sub FindClang { + if (!defined $Options{AnalyzerDiscoveryMethod}) { + $Clang = Cwd::realpath("$RealBin/bin/clang") if (-f "$RealBin/bin/clang"); + if (!defined $Clang || ! -x $Clang) { + $Clang = Cwd::realpath("$RealBin/clang") if (-f "$RealBin/clang"); + } + if (!defined $Clang || ! -x $Clang) { + return "error: Cannot find an executable 'clang' relative to" . + " scan-build. Consider using --use-analyzer to pick a version of" . + " 'clang' to use for static analysis.\n"; + } + } + else { + if ($Options{AnalyzerDiscoveryMethod} =~ /^[Xx]code$/) { + my $xcrun = `which xcrun`; + chomp $xcrun; + if ($xcrun eq "") { + return "Cannot find 'xcrun' to find 'clang' for analysis.\n"; + } + $Clang = `$xcrun -toolchain XcodeDefault -find clang`; + chomp $Clang; + if ($Clang eq "") { + return "No 'clang' executable found by 'xcrun'\n"; + } + } + else { + $Clang = $Options{AnalyzerDiscoveryMethod}; + if (!defined $Clang or not -x $Clang) { + return "Cannot find an executable clang at '$Options{AnalyzerDiscoveryMethod}'\n"; + } + } + } + return undef; +} + +##----------------------------------------------------------------------------## # Process command-line arguments. ##----------------------------------------------------------------------------## -my $AnalyzeHeaders = 0; -my $HtmlDir; # Parent directory to store HTML files. -my $IgnoreErrors = 0; # Ignore build errors. -my $ViewResults = 0; # View results when the build terminates. -my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found -my $KeepEmpty = 0; # Don't remove output directory even with 0 results. -my @AnalysesToRun; -my $StoreModel; -my $ConstraintsModel; -my $InternalStats; -my @ConfigOptions; -my $OutputFormat = "html"; -my $AnalyzerStats = 0; -my $MaxLoop = 0; my $RequestDisplayHelp = 0; my $ForceDisplayHelp = 0; -my $AnalyzerDiscoveryMethod; -if (!@ARGV) { - $ForceDisplayHelp = 1 -} +sub ProcessArgs { + my $Args = shift; + my $NumArgs = 0; -while (@ARGV) { + while (@$Args) { - # Scan for options we recognize. + $NumArgs++; - my $arg = $ARGV[0]; + # Scan for options we recognize. - if ($arg eq "-h" or $arg eq "--help") { - $RequestDisplayHelp = 1; - shift @ARGV; - next; - } + my $arg = $Args->[0]; - if ($arg eq '-analyze-headers') { - shift @ARGV; - $AnalyzeHeaders = 1; - next; - } + if ($arg eq "-h" or $arg eq "--help") { + $RequestDisplayHelp = 1; + shift @$Args; + next; + } - if ($arg eq "-o") { - shift @ARGV; + if ($arg eq '-analyze-headers') { + shift @$Args; + $Options{AnalyzeHeaders} = 1; + next; + } - if (!@ARGV) { - DieDiag("'-o' option requires a target directory name.\n"); + if ($arg eq "-o") { + shift @$Args; + + if (!@$Args) { + DieDiag("'-o' option requires a target directory name.\n"); + } + + # Construct an absolute path. Uses the current working directory + # as a base if the original path was not absolute. + my $OutDir = shift @$Args; + mkpath($OutDir) unless (-e $OutDir); # abs_path wants existing dir + $Options{OutputDir} = abs_path($OutDir); + + next; } - # Construct an absolute path. Uses the current working directory - # as a base if the original path was not absolute. - $HtmlDir = abs_path(shift @ARGV); + if ($arg =~ /^--html-title(=(.+))?$/) { + shift @$Args; - next; - } + if (!defined $2 || $2 eq '') { + if (!@$Args) { + DieDiag("'--html-title' option requires a string.\n"); + } + + $Options{HtmlTitle} = shift @$Args; + } else { + $Options{HtmlTitle} = $2; + } + + next; + } + + if ($arg eq "-k" or $arg eq "--keep-going") { + shift @$Args; + $Options{IgnoreErrors} = 1; + next; + } - if ($arg =~ /^--html-title(=(.+))?$/) { - shift @ARGV; + if ($arg =~ /^--use-cc(=(.+))?$/) { + shift @$Args; + my $cc; - if (!defined $2 || $2 eq '') { - if (!@ARGV) { - DieDiag("'--html-title' option requires a string.\n"); + if (!defined $2 || $2 eq "") { + if (!@$Args) { + DieDiag("'--use-cc' option requires a compiler executable name.\n"); + } + $cc = shift @$Args; + } + else { + $cc = $2; } - $HtmlTitle = shift @ARGV; - } else { - $HtmlTitle = $2; + $Options{UseCC} = $cc; + next; } - next; - } + if ($arg =~ /^--use-c\+\+(=(.+))?$/) { + shift @$Args; + my $cxx; - if ($arg eq "-k" or $arg eq "--keep-going") { - shift @ARGV; - $IgnoreErrors = 1; - next; - } + if (!defined $2 || $2 eq "") { + if (!@$Args) { + DieDiag("'--use-c++' option requires a compiler executable name.\n"); + } + $cxx = shift @$Args; + } + else { + $cxx = $2; + } - if ($arg =~ /^--use-cc(=(.+))?$/) { - shift @ARGV; - my $cc; + $Options{UseCXX} = $cxx; + next; + } - if (!defined $2 || $2 eq "") { - if (!@ARGV) { - DieDiag("'--use-cc' option requires a compiler executable name.\n"); + if ($arg =~ /^--analyzer-target(=(.+))?$/) { + shift @ARGV; + my $AnalyzerTarget; + + if (!defined $2 || $2 eq "") { + if (!@ARGV) { + DieDiag("'--analyzer-target' option requires a target triple name.\n"); + } + $AnalyzerTarget = shift @ARGV; } - $cc = shift @ARGV; + else { + $AnalyzerTarget = $2; + } + + $Options{AnalyzerTarget} = $AnalyzerTarget; + next; } - else { - $cc = $2; + + if ($arg eq "-v") { + shift @$Args; + $Options{Verbose}++; + next; } - $ENV{"CCC_CC"} = $cc; - next; - } + if ($arg eq "-V" or $arg eq "--view") { + shift @$Args; + $Options{ViewResults} = 1; + next; + } - if ($arg =~ /^--use-c\+\+(=(.+))?$/) { - shift @ARGV; - my $cxx; + if ($arg eq "--status-bugs") { + shift @$Args; + $Options{ExitStatusFoundBugs} = 1; + next; + } - if (!defined $2 || $2 eq "") { - if (!@ARGV) { - DieDiag("'--use-c++' option requires a compiler executable name.\n"); - } - $cxx = shift @ARGV; + if ($arg eq "-store") { + shift @$Args; + $Options{StoreModel} = shift @$Args; + next; } - else { - $cxx = $2; + + if ($arg eq "-constraints") { + shift @$Args; + $Options{ConstraintsModel} = shift @$Args; + next; } - $ENV{"CCC_CXX"} = $cxx; - next; - } + if ($arg eq "-internal-stats") { + shift @$Args; + $Options{InternalStats} = 1; + next; + } - if ($arg eq "-v") { - shift @ARGV; - $Verbose++; - next; - } + if ($arg eq "-plist") { + shift @$Args; + $Options{OutputFormat} = "plist"; + next; + } - if ($arg eq "-V" or $arg eq "--view") { - shift @ARGV; - $ViewResults = 1; - next; - } + if ($arg eq "-plist-html") { + shift @$Args; + $Options{OutputFormat} = "plist-html"; + next; + } - if ($arg eq "--status-bugs") { - shift @ARGV; - $ExitStatusFoundBugs = 1; - next; - } + if ($arg eq "-analyzer-config") { + shift @$Args; + push @{$Options{ConfigOptions}}, shift @$Args; + next; + } - if ($arg eq "-store") { - shift @ARGV; - $StoreModel = shift @ARGV; - next; - } + if ($arg eq "-no-failure-reports") { + shift @$Args; + $Options{ReportFailures} = 0; + next; + } - if ($arg eq "-constraints") { - shift @ARGV; - $ConstraintsModel = shift @ARGV; - next; - } + if ($arg eq "-stats") { + shift @$Args; + $Options{AnalyzerStats} = 1; + next; + } - if ($arg eq "-internal-stats") { - shift @ARGV; - $InternalStats = 1; - next; - } + if ($arg eq "-maxloop") { + shift @$Args; + $Options{MaxLoop} = shift @$Args; + next; + } - if ($arg eq "-plist") { - shift @ARGV; - $OutputFormat = "plist"; - next; - } - if ($arg eq "-plist-html") { - shift @ARGV; - $OutputFormat = "plist-html"; - next; - } + if ($arg eq "-enable-checker") { + shift @$Args; + my $Checker = shift @$Args; + # Store $NumArgs to preserve the order the checkers were enabled. + $Options{EnableCheckers}{$Checker} = $NumArgs; + delete $Options{DisableCheckers}{$Checker}; + next; + } - if ($arg eq "-analyzer-config") { - shift @ARGV; - push @ConfigOptions, "-analyzer-config", shift @ARGV; - next; - } + if ($arg eq "-disable-checker") { + shift @$Args; + my $Checker = shift @$Args; + # Store $NumArgs to preserve the order the checkers were disabled. + $Options{DisableCheckers}{$Checker} = $NumArgs; + delete $Options{EnableCheckers}{$Checker}; + next; + } - if ($arg eq "-no-failure-reports") { - shift @ARGV; - $ENV{"CCC_REPORT_FAILURES"} = 0; - next; - } - if ($arg eq "-stats") { - shift @ARGV; - $AnalyzerStats = 1; - next; - } - if ($arg eq "-maxloop") { - shift @ARGV; - $MaxLoop = shift @ARGV; - next; - } - if ($arg eq "-enable-checker") { - shift @ARGV; - push @AnalysesToRun, "-analyzer-checker", shift @ARGV; - next; - } - if ($arg eq "-disable-checker") { - shift @ARGV; - push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV; - next; - } - if ($arg eq "-load-plugin") { - shift @ARGV; - push @PluginsToLoad, "-load", shift @ARGV; - next; - } - if ($arg eq "--use-analyzer") { - shift @ARGV; - $AnalyzerDiscoveryMethod = shift @ARGV; - next; - } - if ($arg =~ /^--use-analyzer=(.+)$/) { - shift @ARGV; - $AnalyzerDiscoveryMethod = $1; - next; - } - if ($arg eq "--keep-empty") { - shift @ARGV; - $KeepEmpty = 1; - next; - } + if ($arg eq "-load-plugin") { + shift @$Args; + push @{$Options{PluginsToLoad}}, shift @$Args; + next; + } - if ($arg eq "--override-compiler") { - shift @ARGV; - $OverrideCompiler = 1; - next; - } + if ($arg eq "--use-analyzer") { + shift @$Args; + $Options{AnalyzerDiscoveryMethod} = shift @$Args; + next; + } - DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/); + if ($arg =~ /^--use-analyzer=(.+)$/) { + shift @$Args; + $Options{AnalyzerDiscoveryMethod} = $1; + next; + } + + if ($arg eq "--keep-empty") { + shift @$Args; + $Options{KeepEmpty} = 1; + next; + } + + if ($arg eq "--override-compiler") { + shift @$Args; + $Options{OverrideCompiler} = 1; + next; + } - last; + DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/); + + $NumArgs--; + last; + } + return $NumArgs; } +if (!@ARGV) { + $ForceDisplayHelp = 1 +} + +ProcessArgs(\@ARGV); +# All arguments are now shifted from @ARGV. The rest is a build command, if any. + if (!@ARGV and !$RequestDisplayHelp) { ErrorDiag("No build command specified.\n\n"); $ForceDisplayHelp = 1; } -# Find 'clang' -if (!defined $AnalyzerDiscoveryMethod) { - $Clang = Cwd::realpath("$RealBin/bin/clang"); - if (!defined $Clang || ! -x $Clang) { - $Clang = Cwd::realpath("$RealBin/clang"); - } - if (!defined $Clang || ! -x $Clang) { - if (!$RequestDisplayHelp && !$ForceDisplayHelp) { - DieDiag("error: Cannot find an executable 'clang' relative to scan-build." . - " Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n"); - } - } -} -else { - if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) { - my $xcrun = `which xcrun`; - chomp $xcrun; - if ($xcrun eq "") { - DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n"); - } - $Clang = `$xcrun -toolchain XcodeDefault -find clang`; - chomp $Clang; - if ($Clang eq "") { - DieDiag("No 'clang' executable found by 'xcrun'\n"); - } - } - else { - $Clang = $AnalyzerDiscoveryMethod; - if (!defined $Clang or not -x $Clang) { - DieDiag("Cannot find an executable clang at '$AnalyzerDiscoveryMethod'\n"); - } - } -} +my $ClangNotFoundErrMsg = FindClang(); if ($ForceDisplayHelp || $RequestDisplayHelp) { - DisplayHelp(); + DisplayHelp($ClangNotFoundErrMsg); exit $ForceDisplayHelp; } +DieDiag($ClangNotFoundErrMsg) if (defined $ClangNotFoundErrMsg); + $ClangCXX = $Clang; -# Determine operating system under which this copy of Perl was built. -my $IsWinBuild = ($^O =~/msys|cygwin|MSWin32/); -if($IsWinBuild) { - $ClangCXX =~ s/.exe$/++.exe/; -} -else { - $ClangCXX =~ s/\-\d+\.\d+$//; - $ClangCXX .= "++"; +if ($Clang !~ /\+\+(\.exe)?$/) { + # If $Clang holds the name of the clang++ executable then we leave + # $ClangCXX and $Clang equal, otherwise construct the name of the clang++ + # executable from the clang executable name. + + # Determine operating system under which this copy of Perl was built. + my $IsWinBuild = ($^O =~/msys|cygwin|MSWin32/); + if($IsWinBuild) { + $ClangCXX =~ s/.exe$/++.exe/; + } + else { + $ClangCXX =~ s/\-\d+\.\d+$//; + $ClangCXX .= "++"; + } } # Make sure to use "" to handle paths with spaces. @@ -1632,17 +1732,15 @@ $ClangVersion = HtmlEscape(`"$Clang" --version`); # Determine where results go. $CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV))); -$HtmlTitle = "${CurrentDirSuffix} - scan-build results" - unless (defined($HtmlTitle)); # Determine the output directory for the HTML reports. -my $BaseDir = $HtmlDir; -$HtmlDir = GetHTMLRunDir($HtmlDir); +my $BaseDir = $Options{OutputDir}; +$Options{OutputDir} = GetHTMLRunDir($Options{OutputDir}); # Determine the location of ccc-analyzer. my $AbsRealBin = Cwd::realpath($RealBin); -my $Cmd = "$AbsRealBin/libexec/ccc-analyzer"; -my $CmdCXX = "$AbsRealBin/libexec/c++-analyzer"; +my $Cmd = "$AbsRealBin/../libexec/ccc-analyzer"; +my $CmdCXX = "$AbsRealBin/../libexec/c++-analyzer"; # Portability: use less strict but portable check -e (file exists) instead of # non-portable -x (file is executable). On some windows ports -x just checks @@ -1659,63 +1757,72 @@ if (!defined $CmdCXX || ! -e $CmdCXX) { Diag("Using '$Clang' for static analysis\n"); -SetHtmlEnv(\@ARGV, $HtmlDir); -if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; } -if ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; } -if ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; } +SetHtmlEnv(\@ARGV, $Options{OutputDir}); + +my @AnalysesToRun; +foreach (sort { $Options{EnableCheckers}{$a} <=> $Options{EnableCheckers}{$b} } + keys %{$Options{EnableCheckers}}) { + # Push checkers in order they were enabled. + push @AnalysesToRun, "-analyzer-checker", $_; +} +foreach (sort { $Options{DisableCheckers}{$a} <=> $Options{DisableCheckers}{$b} } + keys %{$Options{DisableCheckers}}) { + # Push checkers in order they were disabled. + push @AnalysesToRun, "-analyzer-disable-checker", $_; +} +if ($Options{AnalyzeHeaders}) { push @AnalysesToRun, "-analyzer-opt-analyze-headers"; } +if ($Options{AnalyzerStats}) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; } +if ($Options{MaxLoop} > 0) { push @AnalysesToRun, "-analyzer-max-loop $Options{MaxLoop}"; } # Delay setting up other environment variables in case we can do true # interposition. -my $CCC_ANALYZER_ANALYSIS = join ' ',@AnalysesToRun; -my $CCC_ANALYZER_PLUGINS = join ' ',@PluginsToLoad; -my $CCC_ANALYZER_CONFIG = join ' ',@ConfigOptions; -my %Options = ( +my $CCC_ANALYZER_ANALYSIS = join ' ', @AnalysesToRun; +my $CCC_ANALYZER_PLUGINS = join ' ', map { "-load ".$_ } @{$Options{PluginsToLoad}}; +my $CCC_ANALYZER_CONFIG = join ' ', map { "-analyzer-config ".$_ } @{$Options{ConfigOptions}}; +my %EnvVars = ( 'CC' => $Cmd, 'CXX' => $CmdCXX, 'CLANG' => $Clang, 'CLANG_CXX' => $ClangCXX, - 'VERBOSE' => $Verbose, + 'VERBOSE' => $Options{Verbose}, 'CCC_ANALYZER_ANALYSIS' => $CCC_ANALYZER_ANALYSIS, 'CCC_ANALYZER_PLUGINS' => $CCC_ANALYZER_PLUGINS, 'CCC_ANALYZER_CONFIG' => $CCC_ANALYZER_CONFIG, - 'OUTPUT_DIR' => $HtmlDir + 'OUTPUT_DIR' => $Options{OutputDir}, + 'CCC_CC' => $Options{UseCC}, + 'CCC_CXX' => $Options{UseCXX}, + 'CCC_REPORT_FAILURES' => $Options{ReportFailures}, + 'CCC_ANALYZER_STORE_MODEL' => $Options{StoreModel}, + 'CCC_ANALYZER_CONSTRAINTS_MODEL' => $Options{ConstraintsModel}, + 'CCC_ANALYZER_INTERNAL_STATS' => $Options{InternalStats}, + 'CCC_ANALYZER_OUTPUT_FORMAT' => $Options{OutputFormat}, + 'CLANG_ANALYZER_TARGET' => $Options{AnalyzerTarget} ); -if (defined $StoreModel) { - $Options{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel; -} -if (defined $ConstraintsModel) { - $Options{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel; -} -if (defined $InternalStats) { - $Options{'CCC_ANALYZER_INTERNAL_STATS'} = 1; -} -if (defined $OutputFormat) { - $Options{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat; -} - # Run the build. -my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX, - \%Options); +my $ExitStatus = RunBuildCommand(\@ARGV, $Options{IgnoreErrors}, $Cmd, $CmdCXX, + \%EnvVars); -if (defined $OutputFormat) { - if ($OutputFormat =~ /plist/) { +if (defined $Options{OutputFormat}) { + if ($Options{OutputFormat} =~ /plist/) { Diag "Analysis run complete.\n"; - Diag "Analysis results (plist files) deposited in '$HtmlDir'\n"; + Diag "Analysis results (plist files) deposited in '$Options{OutputDir}'\n"; } - if ($OutputFormat =~ /html/) { + if ($Options{OutputFormat} =~ /html/) { # Postprocess the HTML directory. - my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats, $KeepEmpty); + my $NumBugs = Postprocess($Options{OutputDir}, $BaseDir, + $Options{AnalyzerStats}, $Options{KeepEmpty}); - if ($ViewResults and -r "$HtmlDir/index.html") { + if ($Options{ViewResults} and -r "$Options{OutputDir}/index.html") { Diag "Analysis run complete.\n"; - Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n"; + Diag "Viewing analysis results in '$Options{OutputDir}' using scan-view.\n"; my $ScanView = Cwd::realpath("$RealBin/scan-view"); if (! -x $ScanView) { $ScanView = "scan-view"; } - exec $ScanView, "$HtmlDir"; + if (! -x $ScanView) { $ScanView = Cwd::realpath("$RealBin/../../scan-view/bin/scan-view"); } + exec $ScanView, "$Options{OutputDir}"; } - if ($ExitStatusFoundBugs) { + if ($Options{ExitStatusFoundBugs}) { exit 1 if ($NumBugs > 0); exit 0; } diff --git a/tools/scan-build/scan-build.bat b/tools/scan-build/bin/scan-build.bat index 77be674..77be674 100644 --- a/tools/scan-build/scan-build.bat +++ b/tools/scan-build/bin/scan-build.bat diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/bin/set-xcode-analyzer index 8e67482..8e67482 100755 --- a/tools/scan-build/set-xcode-analyzer +++ b/tools/scan-build/bin/set-xcode-analyzer diff --git a/tools/scan-build/c++-analyzer b/tools/scan-build/libexec/c++-analyzer index dda5db9..dda5db9 100755 --- a/tools/scan-build/c++-analyzer +++ b/tools/scan-build/libexec/c++-analyzer diff --git a/tools/scan-build/c++-analyzer.bat b/tools/scan-build/libexec/c++-analyzer.bat index 69f048a..69f048a 100644 --- a/tools/scan-build/c++-analyzer.bat +++ b/tools/scan-build/libexec/c++-analyzer.bat diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/libexec/ccc-analyzer index 14591ae..831dd42 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/libexec/ccc-analyzer @@ -68,6 +68,7 @@ my $Clang; my $DefaultCCompiler; my $DefaultCXXCompiler; my $IsCXX; +my $AnalyzerTarget; # If on OSX, use xcrun to determine the SDK root. my $UseXCRUN = 0; @@ -104,6 +105,8 @@ else { $IsCXX = 0 } +$AnalyzerTarget = $ENV{'CLANG_ANALYZER_TARGET'}; + ##===----------------------------------------------------------------------===## # Cleanup. ##===----------------------------------------------------------------------===## @@ -245,6 +248,10 @@ sub Analyze { push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph"; } + if (defined $AnalyzerTarget) { + push @Args, "-target", $AnalyzerTarget; + } + my $AnalysisArgs = GetCCArgs($HtmlDir, "--analyze", \@Args); @CmdArgs = @$AnalysisArgs; } @@ -275,7 +282,7 @@ sub Analyze { # We save the output file in the 'crashes' directory if clang encounters # any problems with the file. my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir); - + my $OutputStream = silent_system($HtmlDir, $Cmd, @CmdArgs); while ( <$OutputStream> ) { print $ofh $_; @@ -579,7 +586,7 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) { } # Compile mode flags. - if ($Arg =~ /^-[D,I,U,isystem](.*)$/) { + if ($Arg =~ /^-(?:[DIU]|isystem)(.*)$/) { my $Tmp = $Arg; if ($1 eq '') { # FIXME: Check if we are going off the end. @@ -660,6 +667,15 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) { next; } + # Handle -Xclang some-arg. Add both arguments to the compiler options. + if ($Arg =~ /^-Xclang$/) { + # FIXME: Check if we are going off the end. + ++$i; + push @CompileOpts, $Arg; + push @CompileOpts, $ARGV[$i]; + next; + } + if (!($Arg =~ /^-/)) { push @Files, $Arg; next; diff --git a/tools/scan-build/ccc-analyzer.bat b/tools/scan-build/libexec/ccc-analyzer.bat index 2a85376..2a85376 100644 --- a/tools/scan-build/ccc-analyzer.bat +++ b/tools/scan-build/libexec/ccc-analyzer.bat diff --git a/tools/scan-build/scan-build.1 b/tools/scan-build/man/scan-build.1 index 5733364..fd18d1f 100644 --- a/tools/scan-build/scan-build.1 +++ b/tools/scan-build/man/scan-build.1 @@ -1,6 +1,6 @@ .\" This file is distributed under the University of Illinois Open Source .\" License. See LICENSE.TXT for details. -.\" $Id: scan-build.1 201182 2014-02-11 21:37:27Z sylvestre $ +.\" $Id: scan-build.1 253074 2015-11-13 20:34:15Z jroelofs $ .Dd May 25, 2012 .Dt SCAN-BUILD 1 .Os "clang" "3.5" diff --git a/tools/scan-build/scanview.css b/tools/scan-build/share/scan-build/scanview.css index cf8a5a6..cf8a5a6 100644 --- a/tools/scan-build/scanview.css +++ b/tools/scan-build/share/scan-build/scanview.css diff --git a/tools/scan-build/sorttable.js b/tools/scan-build/share/scan-build/sorttable.js index 32faa07..32faa07 100644 --- a/tools/scan-build/sorttable.js +++ b/tools/scan-build/share/scan-build/sorttable.js |