зеркало из https://github.com/microsoft/clang.git
[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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@261204 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
dcd61b3089
Коммит
19b977bcdf
|
@ -106,7 +106,8 @@ def run_analyzer(args, output_dir):
|
||||||
'output_dir': output_dir,
|
'output_dir': output_dir,
|
||||||
'output_format': args.output_format,
|
'output_format': args.output_format,
|
||||||
'output_failures': args.output_failures,
|
'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')
|
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_DIR': destination,
|
||||||
'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
|
'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
|
||||||
'ANALYZE_BUILD_REPORT_FAILURES': 'yes' if args.output_failures else '',
|
'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
|
return environment
|
||||||
|
|
||||||
|
@ -168,6 +171,8 @@ def analyze_build_wrapper(cplusplus):
|
||||||
'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
|
'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
|
||||||
'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
|
'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
|
||||||
'').split(' '),
|
'').split(' '),
|
||||||
|
'force_analyze_debug_code':
|
||||||
|
os.getenv('ANALYZE_BUILD_FORCE_ANALYZE_DEBUG_CODE'),
|
||||||
'directory': os.getcwd(),
|
'directory': os.getcwd(),
|
||||||
}
|
}
|
||||||
# get relevant parameters from command line arguments
|
# 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.
|
Could be usefull when project contains 3rd party libraries.
|
||||||
The directory path shall be absolute path as file names in
|
The directory path shall be absolute path as file names in
|
||||||
the compilation database.""")
|
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 = parser.add_argument_group('checker options')
|
||||||
plugins.add_argument(
|
plugins.add_argument(
|
||||||
|
|
|
@ -41,6 +41,7 @@ def require(required):
|
||||||
|
|
||||||
@require(['command', 'directory', 'file', # an entry from compilation database
|
@require(['command', 'directory', 'file', # an entry from compilation database
|
||||||
'clang', 'direct_args', # compiler name, and arguments from command
|
'clang', 'direct_args', # compiler name, and arguments from command
|
||||||
|
'force_analyze_debug_code', # preprocessing options
|
||||||
'output_dir', 'output_format', 'output_failures'])
|
'output_dir', 'output_format', 'output_failures'])
|
||||||
def run(opts):
|
def run(opts):
|
||||||
""" Entry point to run (or not) static analyzer against a single entry
|
""" 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']]})
|
opts.update({'output': ['-o', opts['output_dir']]})
|
||||||
return continuation(opts)
|
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',
|
@require(['file', 'directory', 'clang', 'direct_args',
|
||||||
'output_dir', 'output_format', 'output_failures'])
|
'force_analyze_debug_code', 'language', 'output_dir',
|
||||||
|
'output_format', 'output_failures'])
|
||||||
def create_commands(opts, continuation=set_analyzer_output):
|
def create_commands(opts, continuation=set_analyzer_output):
|
||||||
""" Create command to run analyzer or failure report generation.
|
""" 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:
|
if 'arch' in opts:
|
||||||
common.extend(['-arch', opts.pop('arch')])
|
common.extend(['-arch', opts.pop('arch')])
|
||||||
common.extend(opts.pop('compile_options', []))
|
common.extend(opts.pop('compile_options', []))
|
||||||
|
if opts['force_analyze_debug_code']:
|
||||||
|
force_analyze_debug_code(common)
|
||||||
common.extend(['-x', opts['language']])
|
common.extend(['-x', opts['language']])
|
||||||
common.append(os.path.relpath(opts['file'], opts['directory']))
|
common.append(os.path.relpath(opts['file'], opts['directory']))
|
||||||
|
|
||||||
|
|
|
@ -211,3 +211,14 @@ class RequireDecoratorTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_method_exception_not_caught(self):
|
def test_method_exception_not_caught(self):
|
||||||
self.assertRaises(Exception, method_exception_from_inside, dict())
|
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)
|
||||||
|
|
|
@ -69,7 +69,8 @@ my %Options = (
|
||||||
MaxLoop => 0,
|
MaxLoop => 0,
|
||||||
PluginsToLoad => [],
|
PluginsToLoad => [],
|
||||||
AnalyzerDiscoveryMethod => undef,
|
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);
|
lock_keys(%Options);
|
||||||
|
|
||||||
|
@ -951,7 +952,8 @@ sub SetEnv {
|
||||||
'CCC_CC',
|
'CCC_CC',
|
||||||
'CCC_CXX',
|
'CCC_CXX',
|
||||||
'CCC_REPORT_FAILURES',
|
'CCC_REPORT_FAILURES',
|
||||||
'CLANG_ANALYZER_TARGET') {
|
'CLANG_ANALYZER_TARGET',
|
||||||
|
'CCC_ANALYZER_FORCE_ANALYZE_DEBUG_CODE') {
|
||||||
my $x = $EnvVars->{$var};
|
my $x = $EnvVars->{$var};
|
||||||
if (defined $x) { $ENV{$var} = $x }
|
if (defined $x) { $ENV{$var} = $x }
|
||||||
}
|
}
|
||||||
|
@ -1118,6 +1120,11 @@ OPTIONS:
|
||||||
Also analyze functions in #included files. By default, such functions
|
Also analyze functions in #included files. By default, such functions
|
||||||
are skipped unless they are called by functions within the main source file.
|
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>
|
-o <output location>
|
||||||
|
|
||||||
Specifies the output directory for analyzer reports. Subdirectories will be
|
Specifies the output directory for analyzer reports. Subdirectories will be
|
||||||
|
@ -1681,6 +1688,12 @@ sub ProcessArgs {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($arg eq "--force-analyze-debug-code") {
|
||||||
|
shift @$Args;
|
||||||
|
$Options{ForceAnalyzeDebugCode} = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
|
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
|
||||||
|
|
||||||
$NumArgs--;
|
$NumArgs--;
|
||||||
|
@ -1796,7 +1809,8 @@ my %EnvVars = (
|
||||||
'CCC_ANALYZER_CONSTRAINTS_MODEL' => $Options{ConstraintsModel},
|
'CCC_ANALYZER_CONSTRAINTS_MODEL' => $Options{ConstraintsModel},
|
||||||
'CCC_ANALYZER_INTERNAL_STATS' => $Options{InternalStats},
|
'CCC_ANALYZER_INTERNAL_STATS' => $Options{InternalStats},
|
||||||
'CCC_ANALYZER_OUTPUT_FORMAT' => $Options{OutputFormat},
|
'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.
|
# Run the build.
|
||||||
|
|
|
@ -492,6 +492,9 @@ if (defined $ENV{'CCC_ANALYZER_LOG'}) { $Verbose = 2; }
|
||||||
# Get the HTML output directory.
|
# Get the HTML output directory.
|
||||||
my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
|
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 %DisabledArchs = ('ppc' => 1, 'ppc64' => 1);
|
||||||
my %ArchsSeen;
|
my %ArchsSeen;
|
||||||
my $HadArch = 0;
|
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
|
# If we are on OSX and have an installation where the
|
||||||
# default SDK is inferred by xcrun use xcrun to infer
|
# default SDK is inferred by xcrun use xcrun to infer
|
||||||
# the SDK.
|
# the SDK.
|
||||||
|
|
|
@ -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
|
in some cases can greatly reduce the number of false positives (bogus error
|
||||||
reports) emitted by the tool.</p>
|
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>
|
<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
|
<p><tt>scan-build</tt> takes a <b>-v</b> option to emit verbose output about
|
||||||
|
|
Загрузка…
Ссылка в новой задаче