]> granicus.if.org Git - clang/commitdiff
[analyzer] Add --force-analyze-debug-code option to scan-build
authorYury Gribov <y.gribov@samsung.com>
Thu, 18 Feb 2016 11:08:46 +0000 (11:08 +0000)
committerYury Gribov <y.gribov@samsung.com>
Thu, 18 Feb 2016 11:08:46 +0000 (11:08 +0000)
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

tools/scan-build-py/libscanbuild/analyze.py
tools/scan-build-py/libscanbuild/runner.py
tools/scan-build-py/tests/unit/test_runner.py
tools/scan-build/bin/scan-build
tools/scan-build/libexec/ccc-analyzer
www/analyzer/scan-build.html

index 0d3547befeef4c3fd907ea173dad31b9c1c982f8..9b00d04fc0f58a02b792237b67a63e24e76755c4 100644 (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(
index 248ca90ad3e6204dafdb6d79feb8126654a55101..63b9f743699f6a669ceb5308867f8f18fde7ffff 100644 (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']))
 
index ea10051d8506f52dbe4713ac2788f345c55c8856..de15d2369207773a0bcdad47f8f30fa5fbd1ed72 100644 (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)
index 6a14484970a2740d0c2c1dd0bd90e555f5a3b178..3182a29767b923658bfdc0f2290ca35104619654 100755 (executable)
@@ -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.
index 831dd42e9c9c0665ecbdb5449d04df9cb21fa567..bfda1d326f90452ab17cd05b1a5b217709b4bf11 100755 (executable)
@@ -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.
index 04e93232a6b3b5d731c0b140fb4e5e899b3eb53f..b16f6bb53fa7cddc0d54e2aaf71ddb127aba7489 100644 (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