[analyzer] Add --force-analyze-debug-code option to scan-build

to force debug build and hopefully enable more precise warnings.

Static Analyzer is much more efficient when built in debug mode
(-UNDEBUG) so we advice users to enable it manually. This may be
inconvenient in case of large complex projects (think about Linux
distros e.g. Android or Tizen). This patch adds a flag to scan-build
which inserts -UNDEBUG automatically.

Differential Revision: http://reviews.llvm.org/D16200

llvm-svn: 261204
This commit is contained in:
Yury Gribov
2016-02-18 11:08:46 +00:00
parent 9c4ed175c2
commit a6560ebe4c
6 changed files with 62 additions and 7 deletions

View File

@@ -106,7 +106,8 @@ def run_analyzer(args, output_dir):
'output_dir': output_dir,
'output_format': args.output_format,
'output_failures': args.output_failures,
'direct_args': analyzer_params(args)
'direct_args': analyzer_params(args),
'force_analyze_debug_code' : args.force_analyze_debug_code
}
logging.debug('run analyzer against compilation database')
@@ -138,7 +139,9 @@ def setup_environment(args, destination, bin_dir):
'ANALYZE_BUILD_REPORT_DIR': destination,
'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
'ANALYZE_BUILD_REPORT_FAILURES': 'yes' if args.output_failures else '',
'ANALYZE_BUILD_PARAMETERS': ' '.join(analyzer_params(args))
'ANALYZE_BUILD_PARAMETERS': ' '.join(analyzer_params(args)),
'ANALYZE_BUILD_FORCE_ANALYZE_DEBUG_CODE'
: 'yes' if args.force_analyze_debug_code else ''
})
return environment
@@ -168,6 +171,8 @@ def analyze_build_wrapper(cplusplus):
'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
'').split(' '),
'force_analyze_debug_code':
os.getenv('ANALYZE_BUILD_FORCE_ANALYZE_DEBUG_CODE'),
'directory': os.getcwd(),
}
# get relevant parameters from command line arguments
@@ -450,6 +455,13 @@ def create_parser(from_build_command):
Could be usefull when project contains 3rd party libraries.
The directory path shall be absolute path as file names in
the compilation database.""")
advanced.add_argument(
'--force-analyze-debug-code',
dest='force_analyze_debug_code',
action='store_true',
help="""Tells analyzer to enable assertions in code even if they were
disabled during compilation, enabling more precise
results.""")
plugins = parser.add_argument_group('checker options')
plugins.add_argument(

View File

@@ -41,6 +41,7 @@ def require(required):
@require(['command', 'directory', 'file', # an entry from compilation database
'clang', 'direct_args', # compiler name, and arguments from command
'force_analyze_debug_code', # preprocessing options
'output_dir', 'output_format', 'output_failures'])
def run(opts):
""" Entry point to run (or not) static analyzer against a single entry
@@ -164,9 +165,13 @@ def set_analyzer_output(opts, continuation=run_analyzer):
opts.update({'output': ['-o', opts['output_dir']]})
return continuation(opts)
def force_analyze_debug_code(cmd):
""" Enable assert()'s by undefining NDEBUG. """
cmd.append('-UNDEBUG')
@require(['file', 'directory', 'clang', 'direct_args', 'language',
'output_dir', 'output_format', 'output_failures'])
@require(['file', 'directory', 'clang', 'direct_args',
'force_analyze_debug_code', 'language', 'output_dir',
'output_format', 'output_failures'])
def create_commands(opts, continuation=set_analyzer_output):
""" Create command to run analyzer or failure report generation.
@@ -178,6 +183,8 @@ def create_commands(opts, continuation=set_analyzer_output):
if 'arch' in opts:
common.extend(['-arch', opts.pop('arch')])
common.extend(opts.pop('compile_options', []))
if opts['force_analyze_debug_code']:
force_analyze_debug_code(common)
common.extend(['-x', opts['language']])
common.append(os.path.relpath(opts['file'], opts['directory']))

View File

@@ -211,3 +211,14 @@ class RequireDecoratorTest(unittest.TestCase):
def test_method_exception_not_caught(self):
self.assertRaises(Exception, method_exception_from_inside, dict())
class ForceAnalyzeDebugTest(unittest.TestCase):
def test_force_analyze_debug_code(self):
for a, b in [
([], ['-UNDEBUG']),
(['-O2'], ['-O2', '-UNDEBUG']),
(['-Dkey=val'], ['-Dkey=val', '-UNDEBUG']),
(['-D', 'NDEBUG'], ['-D', 'NDEBUG', '-UNDEBUG']) ]:
sut.force_analyze_debug_code(a)
self.assertEqual(a, b)

View File

@@ -69,7 +69,8 @@ my %Options = (
MaxLoop => 0,
PluginsToLoad => [],
AnalyzerDiscoveryMethod => undef,
OverrideCompiler => 0 # The flag corresponding to the --override-compiler command line option.
OverrideCompiler => 0, # The flag corresponding to the --override-compiler command line option.
ForceAnalyzeDebugCode => 0
);
lock_keys(%Options);
@@ -951,7 +952,8 @@ sub SetEnv {
'CCC_CC',
'CCC_CXX',
'CCC_REPORT_FAILURES',
'CLANG_ANALYZER_TARGET') {
'CLANG_ANALYZER_TARGET',
'CCC_ANALYZER_FORCE_ANALYZE_DEBUG_CODE') {
my $x = $EnvVars->{$var};
if (defined $x) { $ENV{$var} = $x }
}
@@ -1118,6 +1120,11 @@ OPTIONS:
Also analyze functions in #included files. By default, such functions
are skipped unless they are called by functions within the main source file.
--force-analyze-debug-code
Tells analyzer to enable assertions in code even if they were disabled
during compilation to enable more precise results.
-o <output location>
Specifies the output directory for analyzer reports. Subdirectories will be
@@ -1681,6 +1688,12 @@ sub ProcessArgs {
next;
}
if ($arg eq "--force-analyze-debug-code") {
shift @$Args;
$Options{ForceAnalyzeDebugCode} = 1;
next;
}
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
$NumArgs--;
@@ -1796,7 +1809,8 @@ my %EnvVars = (
'CCC_ANALYZER_CONSTRAINTS_MODEL' => $Options{ConstraintsModel},
'CCC_ANALYZER_INTERNAL_STATS' => $Options{InternalStats},
'CCC_ANALYZER_OUTPUT_FORMAT' => $Options{OutputFormat},
'CLANG_ANALYZER_TARGET' => $Options{AnalyzerTarget}
'CLANG_ANALYZER_TARGET' => $Options{AnalyzerTarget},
'CCC_ANALYZER_FORCE_ANALYZE_DEBUG_CODE' => $Options{ForceAnalyzeDebugCode}
);
# Run the build.

View File

@@ -492,6 +492,9 @@ if (defined $ENV{'CCC_ANALYZER_LOG'}) { $Verbose = 2; }
# Get the HTML output directory.
my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
# Get force-analyze-debug-code option.
my $ForceAnalyzeDebugCode = $ENV{'CCC_ANALYZER_FORCE_ANALYZE_DEBUG_CODE'};
my %DisabledArchs = ('ppc' => 1, 'ppc64' => 1);
my %ArchsSeen;
my $HadArch = 0;
@@ -682,6 +685,11 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
}
}
# Forcedly enable debugging if requested by user.
if ($ForceAnalyzeDebugCode) {
push @CompileOpts, '-UNDEBUG';
}
# If we are on OSX and have an installation where the
# default SDK is inferred by xcrun use xcrun to infer
# the SDK.

View File

@@ -226,6 +226,9 @@ Assertions are picked up by the static analyzer to prune infeasible paths, which
in some cases can greatly reduce the number of false positives (bogus error
reports) emitted by the tool.</p>
<p>Another option is to use <tt>--force-analyze-debug-code</tt> flag of
<b>scan-build</b> tool which would enable assertions automatically.</p>
<h3 id="recommend_verbose">Use verbose output when debugging scan-build</h3>
<p><tt>scan-build</tt> takes a <b>-v</b> option to emit verbose output about