@@ -72,8 +72,9 @@ my %Options = (
7272 MaxLoop => 0,
7373 PluginsToLoad => [],
7474 AnalyzerDiscoveryMethod => undef ,
75- OverrideCompiler => 0, # The flag corresponding to the --override-compiler command line option.
76- ForceAnalyzeDebugCode => 0
75+ OverrideCompiler => 0, # The flag corresponding to the --override-compiler command line option.
76+ ForceAnalyzeDebugCode => 0,
77+ GenerateIndex => 0 # Skip the analysis, only generate index.html.
7778);
7879lock_keys(%Options );
7980
@@ -596,9 +597,11 @@ sub Postprocess {
596597 return 0;
597598 }
598599
599- # Scan each report file and build an index.
600+ # Scan each report file, in alphabetical order, and build an index.
600601 my @Index ;
601602 my @Stats ;
603+
604+ @filesFound = sort @filesFound ;
602605 foreach my $file (@filesFound ) { ScanFile(\@Index , $Dir , $file , \@Stats ); }
603606
604607 # Scan the failures directory and use the information in the .info files
@@ -946,6 +949,41 @@ ENDTEXT
946949 return $Num ;
947950}
948951
952+ sub Finalize {
953+ my $BaseDir = shift ;
954+ my $ExitStatus = shift ;
955+
956+ Diag " Analysis run complete.\n " ;
957+ if (defined $Options {OutputFormat }) {
958+ if ($Options {OutputFormat } =~ / plist/ ||
959+ $Options {OutputFormat } =~ / sarif/ ) {
960+ Diag " Analysis results (" .
961+ ($Options {OutputFormat } =~ / plist/ ? " plist" : " sarif" ) .
962+ " files) deposited in '$Options {OutputDir}'\n " ;
963+ }
964+ if ($Options {OutputFormat } =~ / html/ ) {
965+ # Postprocess the HTML directory.
966+ my $NumBugs = Postprocess($Options {OutputDir }, $BaseDir ,
967+ $Options {AnalyzerStats }, $Options {KeepEmpty });
968+
969+ if ($Options {ViewResults } and -r " $Options {OutputDir}/index.html" ) {
970+ Diag " Viewing analysis results in '$Options {OutputDir}' using scan-view.\n " ;
971+ my $ScanView = Cwd::realpath(" $RealBin /scan-view" );
972+ if (! -x $ScanView ) { $ScanView = " scan-view" ; }
973+ if (! -x $ScanView ) { $ScanView = Cwd::realpath(" $RealBin /../../scan-view/bin/scan-view" ); }
974+ exec $ScanView , " $Options {OutputDir}" ;
975+ }
976+
977+ if ($Options {ExitStatusFoundBugs }) {
978+ exit 1 if ($NumBugs > 0);
979+ exit $ExitStatus ;
980+ }
981+ }
982+ }
983+
984+ exit $ExitStatus ;
985+ }
986+
949987# #----------------------------------------------------------------------------##
950988# RunBuildCommand - Run the build command.
951989# #----------------------------------------------------------------------------##
@@ -1259,6 +1297,12 @@ OPTIONS:
12591297
12601298 View analysis results in a web browser when the build completes.
12611299
1300+ --generate-index-only <output location>
1301+
1302+ Do not perform the analysis, but only regenerate the index.html file
1303+ from existing report.html files. Useful for making a custom Static Analyzer
1304+ integration into a build system that isn't otherwise supported by scan-build.
1305+
12621306ADVANCED OPTIONS:
12631307
12641308 -no-failure-reports
@@ -1550,6 +1594,10 @@ sub ProcessArgs {
15501594 }
15511595
15521596 if ($arg eq " -o" ) {
1597+ if (defined ($Options {OutputDir })) {
1598+ DieDiag(" Only one of '-o' or '--generate-index-only' can be specified.\n " );
1599+ }
1600+
15531601 shift @$Args ;
15541602
15551603 if (!@$Args ) {
@@ -1565,6 +1613,27 @@ sub ProcessArgs {
15651613 next ;
15661614 }
15671615
1616+ if ($arg eq " --generate-index-only" ) {
1617+ if (defined ($Options {OutputDir })) {
1618+ DieDiag(" Only one of '-o' or '--generate-index-only' can be specified.\n " );
1619+ }
1620+
1621+ shift @$Args ;
1622+
1623+ if (!@$Args ) {
1624+ DieDiag(" '--generate-index-only' option requires a target directory name.\n " );
1625+ }
1626+
1627+ # Construct an absolute path. Uses the current working directory
1628+ # as a base if the original path was not absolute.
1629+ my $OutDir = shift @$Args ;
1630+ mkpath($OutDir ) unless (-e $OutDir ); # abs_path wants existing dir
1631+ $Options {OutputDir } = abs_path($OutDir );
1632+ $Options {GenerateIndex } = 1;
1633+
1634+ next ;
1635+ }
1636+
15681637 if ($arg =~ / ^--html-title(=(.+))?$ / ) {
15691638 shift @$Args ;
15701639
@@ -1815,18 +1884,32 @@ if (!@ARGV) {
18151884ProcessArgs(\@ARGV );
18161885# All arguments are now shifted from @ARGV. The rest is a build command, if any.
18171886
1818- if (!@ARGV and !$RequestDisplayHelp ) {
1819- ErrorDiag(" No build command specified.\n\n " );
1820- $ForceDisplayHelp = 1;
1821- }
1822-
18231887my $ClangNotFoundErrMsg = FindClang();
18241888
18251889if ($ForceDisplayHelp || $RequestDisplayHelp ) {
18261890 DisplayHelp($ClangNotFoundErrMsg );
18271891 exit $ForceDisplayHelp ;
18281892}
18291893
1894+ $CmdArgs = HtmlEscape(join (' ' , map (ShellEscape($_ ), @ARGV )));
1895+
1896+ if ($Options {GenerateIndex }) {
1897+ $ClangVersion = " unknown" ;
1898+ Finalize($Options {OutputDir }, 0);
1899+ }
1900+
1901+ # Make sure to use "" to handle paths with spaces.
1902+ $ClangVersion = HtmlEscape(` "$Clang " --version` );
1903+
1904+ if (!@ARGV and !$RequestDisplayHelp ) {
1905+ ErrorDiag(" No build command specified.\n\n " );
1906+ $ForceDisplayHelp = 1;
1907+ }
1908+
1909+ # Determine the output directory for the HTML reports.
1910+ my $BaseDir = $Options {OutputDir };
1911+ $Options {OutputDir } = GetHTMLRunDir($Options {OutputDir });
1912+
18301913DieDiag($ClangNotFoundErrMsg ) if (defined $ClangNotFoundErrMsg );
18311914
18321915$ClangCXX = $Clang ;
@@ -1846,16 +1929,6 @@ if ($Clang !~ /\+\+(\.exe)?$/) {
18461929 }
18471930}
18481931
1849- # Make sure to use "" to handle paths with spaces.
1850- $ClangVersion = HtmlEscape(` "$Clang " --version` );
1851-
1852- # Determine where results go.
1853- $CmdArgs = HtmlEscape(join (' ' , map (ShellEscape($_ ), @ARGV )));
1854-
1855- # Determine the output directory for the HTML reports.
1856- my $BaseDir = $Options {OutputDir };
1857- $Options {OutputDir } = GetHTMLRunDir($Options {OutputDir });
1858-
18591932# Determine the location of ccc-analyzer.
18601933my $AbsRealBin = Cwd::realpath($RealBin );
18611934my $Cmd = " $AbsRealBin /../libexec/ccc-analyzer" ;
@@ -1931,33 +2004,4 @@ my %EnvVars = (
19312004my $ExitStatus = RunBuildCommand(\@ARGV , $Options {IgnoreErrors }, $Options {KeepCC },
19322005 $Cmd , $CmdCXX , \%EnvVars );
19332006
1934- if (defined $Options {OutputFormat }) {
1935- if ($Options {OutputFormat } =~ / plist/ ||
1936- $Options {OutputFormat } =~ / sarif/ ) {
1937- Diag " Analysis run complete.\n " ;
1938- Diag " Analysis results (" .
1939- ($Options {OutputFormat } =~ / plist/ ? " plist" : " sarif" ) .
1940- " files) deposited in '$Options {OutputDir}'\n " ;
1941- }
1942- if ($Options {OutputFormat } =~ / html/ ) {
1943- # Postprocess the HTML directory.
1944- my $NumBugs = Postprocess($Options {OutputDir }, $BaseDir ,
1945- $Options {AnalyzerStats }, $Options {KeepEmpty });
1946-
1947- if ($Options {ViewResults } and -r " $Options {OutputDir}/index.html" ) {
1948- Diag " Analysis run complete.\n " ;
1949- Diag " Viewing analysis results in '$Options {OutputDir}' using scan-view.\n " ;
1950- my $ScanView = Cwd::realpath(" $RealBin /scan-view" );
1951- if (! -x $ScanView ) { $ScanView = " scan-view" ; }
1952- if (! -x $ScanView ) { $ScanView = Cwd::realpath(" $RealBin /../../scan-view/bin/scan-view" ); }
1953- exec $ScanView , " $Options {OutputDir}" ;
1954- }
1955-
1956- if ($Options {ExitStatusFoundBugs }) {
1957- exit 1 if ($NumBugs > 0);
1958- exit $ExitStatus ;
1959- }
1960- }
1961- }
1962-
1963- exit $ExitStatus ;
2007+ Finalize($BaseDir , $ExitStatus );
0 commit comments