xref: /openbsd-src/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/arguments.py (revision a9ac8606c53d55cee9c3a39778b249c51df111ef)
1*a9ac8606Spatrick# -*- coding: utf-8 -*-
2*a9ac8606Spatrick# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3*a9ac8606Spatrick# See https://llvm.org/LICENSE.txt for license information.
4*a9ac8606Spatrick# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5*a9ac8606Spatrick""" This module parses and validates arguments for command-line interfaces.
6*a9ac8606Spatrick
7*a9ac8606SpatrickIt uses argparse module to create the command line parser. (This library is
8*a9ac8606Spatrickin the standard python library since 3.2 and backported to 2.7, but not
9*a9ac8606Spatrickearlier.)
10*a9ac8606Spatrick
11*a9ac8606SpatrickIt also implements basic validation methods, related to the command.
12*a9ac8606SpatrickValidations are mostly calling specific help methods, or mangling values.
13*a9ac8606Spatrick"""
14*a9ac8606Spatrickfrom __future__ import absolute_import, division, print_function
15*a9ac8606Spatrick
16*a9ac8606Spatrickimport os
17*a9ac8606Spatrickimport sys
18*a9ac8606Spatrickimport argparse
19*a9ac8606Spatrickimport logging
20*a9ac8606Spatrickimport tempfile
21*a9ac8606Spatrickfrom libscanbuild import reconfigure_logging, CtuConfig
22*a9ac8606Spatrickfrom libscanbuild.clang import get_checkers, is_ctu_capable
23*a9ac8606Spatrick
24*a9ac8606Spatrick__all__ = ['parse_args_for_intercept_build', 'parse_args_for_analyze_build',
25*a9ac8606Spatrick           'parse_args_for_scan_build']
26*a9ac8606Spatrick
27*a9ac8606Spatrick
28*a9ac8606Spatrickdef parse_args_for_intercept_build():
29*a9ac8606Spatrick    """ Parse and validate command-line arguments for intercept-build. """
30*a9ac8606Spatrick
31*a9ac8606Spatrick    parser = create_intercept_parser()
32*a9ac8606Spatrick    args = parser.parse_args()
33*a9ac8606Spatrick
34*a9ac8606Spatrick    reconfigure_logging(args.verbose)
35*a9ac8606Spatrick    logging.debug('Raw arguments %s', sys.argv)
36*a9ac8606Spatrick
37*a9ac8606Spatrick    # short validation logic
38*a9ac8606Spatrick    if not args.build:
39*a9ac8606Spatrick        parser.error(message='missing build command')
40*a9ac8606Spatrick
41*a9ac8606Spatrick    logging.debug('Parsed arguments: %s', args)
42*a9ac8606Spatrick    return args
43*a9ac8606Spatrick
44*a9ac8606Spatrick
45*a9ac8606Spatrickdef parse_args_for_analyze_build():
46*a9ac8606Spatrick    """ Parse and validate command-line arguments for analyze-build. """
47*a9ac8606Spatrick
48*a9ac8606Spatrick    from_build_command = False
49*a9ac8606Spatrick    parser = create_analyze_parser(from_build_command)
50*a9ac8606Spatrick    args = parser.parse_args()
51*a9ac8606Spatrick
52*a9ac8606Spatrick    reconfigure_logging(args.verbose)
53*a9ac8606Spatrick    logging.debug('Raw arguments %s', sys.argv)
54*a9ac8606Spatrick
55*a9ac8606Spatrick    normalize_args_for_analyze(args, from_build_command)
56*a9ac8606Spatrick    validate_args_for_analyze(parser, args, from_build_command)
57*a9ac8606Spatrick    logging.debug('Parsed arguments: %s', args)
58*a9ac8606Spatrick    return args
59*a9ac8606Spatrick
60*a9ac8606Spatrick
61*a9ac8606Spatrickdef parse_args_for_scan_build():
62*a9ac8606Spatrick    """ Parse and validate command-line arguments for scan-build. """
63*a9ac8606Spatrick
64*a9ac8606Spatrick    from_build_command = True
65*a9ac8606Spatrick    parser = create_analyze_parser(from_build_command)
66*a9ac8606Spatrick    args = parser.parse_args()
67*a9ac8606Spatrick
68*a9ac8606Spatrick    reconfigure_logging(args.verbose)
69*a9ac8606Spatrick    logging.debug('Raw arguments %s', sys.argv)
70*a9ac8606Spatrick
71*a9ac8606Spatrick    normalize_args_for_analyze(args, from_build_command)
72*a9ac8606Spatrick    validate_args_for_analyze(parser, args, from_build_command)
73*a9ac8606Spatrick    logging.debug('Parsed arguments: %s', args)
74*a9ac8606Spatrick    return args
75*a9ac8606Spatrick
76*a9ac8606Spatrick
77*a9ac8606Spatrickdef normalize_args_for_analyze(args, from_build_command):
78*a9ac8606Spatrick    """ Normalize parsed arguments for analyze-build and scan-build.
79*a9ac8606Spatrick
80*a9ac8606Spatrick    :param args: Parsed argument object. (Will be mutated.)
81*a9ac8606Spatrick    :param from_build_command: Boolean value tells is the command suppose
82*a9ac8606Spatrick    to run the analyzer against a build command or a compilation db. """
83*a9ac8606Spatrick
84*a9ac8606Spatrick    # make plugins always a list. (it might be None when not specified.)
85*a9ac8606Spatrick    if args.plugins is None:
86*a9ac8606Spatrick        args.plugins = []
87*a9ac8606Spatrick
88*a9ac8606Spatrick    # make exclude directory list unique and absolute.
89*a9ac8606Spatrick    uniq_excludes = set(os.path.abspath(entry) for entry in args.excludes)
90*a9ac8606Spatrick    args.excludes = list(uniq_excludes)
91*a9ac8606Spatrick
92*a9ac8606Spatrick    # because shared codes for all tools, some common used methods are
93*a9ac8606Spatrick    # expecting some argument to be present. so, instead of query the args
94*a9ac8606Spatrick    # object about the presence of the flag, we fake it here. to make those
95*a9ac8606Spatrick    # methods more readable. (it's an arguable choice, took it only for those
96*a9ac8606Spatrick    # which have good default value.)
97*a9ac8606Spatrick    if from_build_command:
98*a9ac8606Spatrick        # add cdb parameter invisibly to make report module working.
99*a9ac8606Spatrick        args.cdb = 'compile_commands.json'
100*a9ac8606Spatrick
101*a9ac8606Spatrick    # Make ctu_dir an abspath as it is needed inside clang
102*a9ac8606Spatrick    if not from_build_command and hasattr(args, 'ctu_phases') \
103*a9ac8606Spatrick            and hasattr(args.ctu_phases, 'dir'):
104*a9ac8606Spatrick        args.ctu_dir = os.path.abspath(args.ctu_dir)
105*a9ac8606Spatrick
106*a9ac8606Spatrick
107*a9ac8606Spatrickdef validate_args_for_analyze(parser, args, from_build_command):
108*a9ac8606Spatrick    """ Command line parsing is done by the argparse module, but semantic
109*a9ac8606Spatrick    validation still needs to be done. This method is doing it for
110*a9ac8606Spatrick    analyze-build and scan-build commands.
111*a9ac8606Spatrick
112*a9ac8606Spatrick    :param parser: The command line parser object.
113*a9ac8606Spatrick    :param args: Parsed argument object.
114*a9ac8606Spatrick    :param from_build_command: Boolean value tells is the command suppose
115*a9ac8606Spatrick    to run the analyzer against a build command or a compilation db.
116*a9ac8606Spatrick    :return: No return value, but this call might throw when validation
117*a9ac8606Spatrick    fails. """
118*a9ac8606Spatrick
119*a9ac8606Spatrick    if args.help_checkers_verbose:
120*a9ac8606Spatrick        print_checkers(get_checkers(args.clang, args.plugins))
121*a9ac8606Spatrick        parser.exit(status=0)
122*a9ac8606Spatrick    elif args.help_checkers:
123*a9ac8606Spatrick        print_active_checkers(get_checkers(args.clang, args.plugins))
124*a9ac8606Spatrick        parser.exit(status=0)
125*a9ac8606Spatrick    elif from_build_command and not args.build:
126*a9ac8606Spatrick        parser.error(message='missing build command')
127*a9ac8606Spatrick    elif not from_build_command and not os.path.exists(args.cdb):
128*a9ac8606Spatrick        parser.error(message='compilation database is missing')
129*a9ac8606Spatrick
130*a9ac8606Spatrick    # If the user wants CTU mode
131*a9ac8606Spatrick    if not from_build_command and hasattr(args, 'ctu_phases') \
132*a9ac8606Spatrick            and hasattr(args.ctu_phases, 'dir'):
133*a9ac8606Spatrick        # If CTU analyze_only, the input directory should exist
134*a9ac8606Spatrick        if args.ctu_phases.analyze and not args.ctu_phases.collect \
135*a9ac8606Spatrick                and not os.path.exists(args.ctu_dir):
136*a9ac8606Spatrick            parser.error(message='missing CTU directory')
137*a9ac8606Spatrick        # Check CTU capability via checking clang-extdef-mapping
138*a9ac8606Spatrick        if not is_ctu_capable(args.extdef_map_cmd):
139*a9ac8606Spatrick            parser.error(message="""This version of clang does not support CTU
140*a9ac8606Spatrick            functionality or clang-extdef-mapping command not found.""")
141*a9ac8606Spatrick
142*a9ac8606Spatrick
143*a9ac8606Spatrickdef create_intercept_parser():
144*a9ac8606Spatrick    """ Creates a parser for command-line arguments to 'intercept'. """
145*a9ac8606Spatrick
146*a9ac8606Spatrick    parser = create_default_parser()
147*a9ac8606Spatrick    parser_add_cdb(parser)
148*a9ac8606Spatrick
149*a9ac8606Spatrick    parser_add_prefer_wrapper(parser)
150*a9ac8606Spatrick    parser_add_compilers(parser)
151*a9ac8606Spatrick
152*a9ac8606Spatrick    advanced = parser.add_argument_group('advanced options')
153*a9ac8606Spatrick    group = advanced.add_mutually_exclusive_group()
154*a9ac8606Spatrick    group.add_argument(
155*a9ac8606Spatrick        '--append',
156*a9ac8606Spatrick        action='store_true',
157*a9ac8606Spatrick        help="""Extend existing compilation database with new entries.
158*a9ac8606Spatrick        Duplicate entries are detected and not present in the final output.
159*a9ac8606Spatrick        The output is not continuously updated, it's done when the build
160*a9ac8606Spatrick        command finished. """)
161*a9ac8606Spatrick
162*a9ac8606Spatrick    parser.add_argument(
163*a9ac8606Spatrick        dest='build', nargs=argparse.REMAINDER, help="""Command to run.""")
164*a9ac8606Spatrick    return parser
165*a9ac8606Spatrick
166*a9ac8606Spatrick
167*a9ac8606Spatrickdef create_analyze_parser(from_build_command):
168*a9ac8606Spatrick    """ Creates a parser for command-line arguments to 'analyze'. """
169*a9ac8606Spatrick
170*a9ac8606Spatrick    parser = create_default_parser()
171*a9ac8606Spatrick
172*a9ac8606Spatrick    if from_build_command:
173*a9ac8606Spatrick        parser_add_prefer_wrapper(parser)
174*a9ac8606Spatrick        parser_add_compilers(parser)
175*a9ac8606Spatrick
176*a9ac8606Spatrick        parser.add_argument(
177*a9ac8606Spatrick            '--intercept-first',
178*a9ac8606Spatrick            action='store_true',
179*a9ac8606Spatrick            help="""Run the build commands first, intercept compiler
180*a9ac8606Spatrick            calls and then run the static analyzer afterwards.
181*a9ac8606Spatrick            Generally speaking it has better coverage on build commands.
182*a9ac8606Spatrick            With '--override-compiler' it use compiler wrapper, but does
183*a9ac8606Spatrick            not run the analyzer till the build is finished.""")
184*a9ac8606Spatrick    else:
185*a9ac8606Spatrick        parser_add_cdb(parser)
186*a9ac8606Spatrick
187*a9ac8606Spatrick    parser.add_argument(
188*a9ac8606Spatrick        '--status-bugs',
189*a9ac8606Spatrick        action='store_true',
190*a9ac8606Spatrick        help="""The exit status of '%(prog)s' is the same as the executed
191*a9ac8606Spatrick        build command. This option ignores the build exit status and sets to
192*a9ac8606Spatrick        be non zero if it found potential bugs or zero otherwise.""")
193*a9ac8606Spatrick    parser.add_argument(
194*a9ac8606Spatrick        '--exclude',
195*a9ac8606Spatrick        metavar='<directory>',
196*a9ac8606Spatrick        dest='excludes',
197*a9ac8606Spatrick        action='append',
198*a9ac8606Spatrick        default=[],
199*a9ac8606Spatrick        help="""Do not run static analyzer against files found in this
200*a9ac8606Spatrick        directory. (You can specify this option multiple times.)
201*a9ac8606Spatrick        Could be useful when project contains 3rd party libraries.""")
202*a9ac8606Spatrick
203*a9ac8606Spatrick    output = parser.add_argument_group('output control options')
204*a9ac8606Spatrick    output.add_argument(
205*a9ac8606Spatrick        '--output',
206*a9ac8606Spatrick        '-o',
207*a9ac8606Spatrick        metavar='<path>',
208*a9ac8606Spatrick        default=tempfile.gettempdir(),
209*a9ac8606Spatrick        help="""Specifies the output directory for analyzer reports.
210*a9ac8606Spatrick        Subdirectory will be created if default directory is targeted.""")
211*a9ac8606Spatrick    output.add_argument(
212*a9ac8606Spatrick        '--keep-empty',
213*a9ac8606Spatrick        action='store_true',
214*a9ac8606Spatrick        help="""Don't remove the build results directory even if no issues
215*a9ac8606Spatrick        were reported.""")
216*a9ac8606Spatrick    output.add_argument(
217*a9ac8606Spatrick        '--html-title',
218*a9ac8606Spatrick        metavar='<title>',
219*a9ac8606Spatrick        help="""Specify the title used on generated HTML pages.
220*a9ac8606Spatrick        If not specified, a default title will be used.""")
221*a9ac8606Spatrick    format_group = output.add_mutually_exclusive_group()
222*a9ac8606Spatrick    format_group.add_argument(
223*a9ac8606Spatrick        '--plist',
224*a9ac8606Spatrick        '-plist',
225*a9ac8606Spatrick        dest='output_format',
226*a9ac8606Spatrick        const='plist',
227*a9ac8606Spatrick        default='html',
228*a9ac8606Spatrick        action='store_const',
229*a9ac8606Spatrick        help="""Cause the results as a set of .plist files.""")
230*a9ac8606Spatrick    format_group.add_argument(
231*a9ac8606Spatrick        '--plist-html',
232*a9ac8606Spatrick        '-plist-html',
233*a9ac8606Spatrick        dest='output_format',
234*a9ac8606Spatrick        const='plist-html',
235*a9ac8606Spatrick        default='html',
236*a9ac8606Spatrick        action='store_const',
237*a9ac8606Spatrick        help="""Cause the results as a set of .html and .plist files.""")
238*a9ac8606Spatrick    format_group.add_argument(
239*a9ac8606Spatrick        '--plist-multi-file',
240*a9ac8606Spatrick        '-plist-multi-file',
241*a9ac8606Spatrick        dest='output_format',
242*a9ac8606Spatrick        const='plist-multi-file',
243*a9ac8606Spatrick        default='html',
244*a9ac8606Spatrick        action='store_const',
245*a9ac8606Spatrick        help="""Cause the results as a set of .plist files with extra
246*a9ac8606Spatrick        information on related files.""")
247*a9ac8606Spatrick    format_group.add_argument(
248*a9ac8606Spatrick        '--sarif',
249*a9ac8606Spatrick        '-sarif',
250*a9ac8606Spatrick        dest='output_format',
251*a9ac8606Spatrick        const='sarif',
252*a9ac8606Spatrick        default='html',
253*a9ac8606Spatrick        action='store_const',
254*a9ac8606Spatrick        help="""Cause the results as a result.sarif file.""")
255*a9ac8606Spatrick    format_group.add_argument(
256*a9ac8606Spatrick        '--sarif-html',
257*a9ac8606Spatrick        '-sarif-html',
258*a9ac8606Spatrick        dest='output_format',
259*a9ac8606Spatrick        const='sarif-html',
260*a9ac8606Spatrick        default='html',
261*a9ac8606Spatrick        action='store_const',
262*a9ac8606Spatrick        help="""Cause the results as a result.sarif file and .html files.""")
263*a9ac8606Spatrick
264*a9ac8606Spatrick    advanced = parser.add_argument_group('advanced options')
265*a9ac8606Spatrick    advanced.add_argument(
266*a9ac8606Spatrick        '--use-analyzer',
267*a9ac8606Spatrick        metavar='<path>',
268*a9ac8606Spatrick        dest='clang',
269*a9ac8606Spatrick        default='clang',
270*a9ac8606Spatrick        help="""'%(prog)s' uses the 'clang' executable relative to itself for
271*a9ac8606Spatrick        static analysis. One can override this behavior with this option by
272*a9ac8606Spatrick        using the 'clang' packaged with Xcode (on OS X) or from the PATH.""")
273*a9ac8606Spatrick    advanced.add_argument(
274*a9ac8606Spatrick        '--no-failure-reports',
275*a9ac8606Spatrick        '-no-failure-reports',
276*a9ac8606Spatrick        dest='output_failures',
277*a9ac8606Spatrick        action='store_false',
278*a9ac8606Spatrick        help="""Do not create a 'failures' subdirectory that includes analyzer
279*a9ac8606Spatrick        crash reports and preprocessed source files.""")
280*a9ac8606Spatrick    parser.add_argument(
281*a9ac8606Spatrick        '--analyze-headers',
282*a9ac8606Spatrick        action='store_true',
283*a9ac8606Spatrick        help="""Also analyze functions in #included files. By default, such
284*a9ac8606Spatrick        functions are skipped unless they are called by functions within the
285*a9ac8606Spatrick        main source file.""")
286*a9ac8606Spatrick    advanced.add_argument(
287*a9ac8606Spatrick        '--stats',
288*a9ac8606Spatrick        '-stats',
289*a9ac8606Spatrick        action='store_true',
290*a9ac8606Spatrick        help="""Generates visitation statistics for the project.""")
291*a9ac8606Spatrick    advanced.add_argument(
292*a9ac8606Spatrick        '--internal-stats',
293*a9ac8606Spatrick        action='store_true',
294*a9ac8606Spatrick        help="""Generate internal analyzer statistics.""")
295*a9ac8606Spatrick    advanced.add_argument(
296*a9ac8606Spatrick        '--maxloop',
297*a9ac8606Spatrick        '-maxloop',
298*a9ac8606Spatrick        metavar='<loop count>',
299*a9ac8606Spatrick        type=int,
300*a9ac8606Spatrick        help="""Specify the number of times a block can be visited before
301*a9ac8606Spatrick        giving up. Increase for more comprehensive coverage at a cost of
302*a9ac8606Spatrick        speed.""")
303*a9ac8606Spatrick    advanced.add_argument(
304*a9ac8606Spatrick        '--store',
305*a9ac8606Spatrick        '-store',
306*a9ac8606Spatrick        metavar='<model>',
307*a9ac8606Spatrick        dest='store_model',
308*a9ac8606Spatrick        choices=['region', 'basic'],
309*a9ac8606Spatrick        help="""Specify the store model used by the analyzer. 'region'
310*a9ac8606Spatrick        specifies a field- sensitive store model. 'basic' which is far less
311*a9ac8606Spatrick        precise but can more quickly analyze code. 'basic' was the default
312*a9ac8606Spatrick        store model for checker-0.221 and earlier.""")
313*a9ac8606Spatrick    advanced.add_argument(
314*a9ac8606Spatrick        '--constraints',
315*a9ac8606Spatrick        '-constraints',
316*a9ac8606Spatrick        metavar='<model>',
317*a9ac8606Spatrick        dest='constraints_model',
318*a9ac8606Spatrick        choices=['range', 'basic'],
319*a9ac8606Spatrick        help="""Specify the constraint engine used by the analyzer. Specifying
320*a9ac8606Spatrick        'basic' uses a simpler, less powerful constraint model used by
321*a9ac8606Spatrick        checker-0.160 and earlier.""")
322*a9ac8606Spatrick    advanced.add_argument(
323*a9ac8606Spatrick        '--analyzer-config',
324*a9ac8606Spatrick        '-analyzer-config',
325*a9ac8606Spatrick        metavar='<options>',
326*a9ac8606Spatrick        help="""Provide options to pass through to the analyzer's
327*a9ac8606Spatrick        -analyzer-config flag. Several options are separated with comma:
328*a9ac8606Spatrick        'key1=val1,key2=val2'
329*a9ac8606Spatrick
330*a9ac8606Spatrick        Available options:
331*a9ac8606Spatrick            stable-report-filename=true or false (default)
332*a9ac8606Spatrick
333*a9ac8606Spatrick        Switch the page naming to:
334*a9ac8606Spatrick        report-<filename>-<function/method name>-<id>.html
335*a9ac8606Spatrick        instead of report-XXXXXX.html""")
336*a9ac8606Spatrick    advanced.add_argument(
337*a9ac8606Spatrick        '--force-analyze-debug-code',
338*a9ac8606Spatrick        dest='force_debug',
339*a9ac8606Spatrick        action='store_true',
340*a9ac8606Spatrick        help="""Tells analyzer to enable assertions in code even if they were
341*a9ac8606Spatrick        disabled during compilation, enabling more precise results.""")
342*a9ac8606Spatrick
343*a9ac8606Spatrick    plugins = parser.add_argument_group('checker options')
344*a9ac8606Spatrick    plugins.add_argument(
345*a9ac8606Spatrick        '--load-plugin',
346*a9ac8606Spatrick        '-load-plugin',
347*a9ac8606Spatrick        metavar='<plugin library>',
348*a9ac8606Spatrick        dest='plugins',
349*a9ac8606Spatrick        action='append',
350*a9ac8606Spatrick        help="""Loading external checkers using the clang plugin interface.""")
351*a9ac8606Spatrick    plugins.add_argument(
352*a9ac8606Spatrick        '--enable-checker',
353*a9ac8606Spatrick        '-enable-checker',
354*a9ac8606Spatrick        metavar='<checker name>',
355*a9ac8606Spatrick        action=AppendCommaSeparated,
356*a9ac8606Spatrick        help="""Enable specific checker.""")
357*a9ac8606Spatrick    plugins.add_argument(
358*a9ac8606Spatrick        '--disable-checker',
359*a9ac8606Spatrick        '-disable-checker',
360*a9ac8606Spatrick        metavar='<checker name>',
361*a9ac8606Spatrick        action=AppendCommaSeparated,
362*a9ac8606Spatrick        help="""Disable specific checker.""")
363*a9ac8606Spatrick    plugins.add_argument(
364*a9ac8606Spatrick        '--help-checkers',
365*a9ac8606Spatrick        action='store_true',
366*a9ac8606Spatrick        help="""A default group of checkers is run unless explicitly disabled.
367*a9ac8606Spatrick        Exactly which checkers constitute the default group is a function of
368*a9ac8606Spatrick        the operating system in use. These can be printed with this flag.""")
369*a9ac8606Spatrick    plugins.add_argument(
370*a9ac8606Spatrick        '--help-checkers-verbose',
371*a9ac8606Spatrick        action='store_true',
372*a9ac8606Spatrick        help="""Print all available checkers and mark the enabled ones.""")
373*a9ac8606Spatrick
374*a9ac8606Spatrick    if from_build_command:
375*a9ac8606Spatrick        parser.add_argument(
376*a9ac8606Spatrick            dest='build', nargs=argparse.REMAINDER, help="""Command to run.""")
377*a9ac8606Spatrick    else:
378*a9ac8606Spatrick        ctu = parser.add_argument_group('cross translation unit analysis')
379*a9ac8606Spatrick        ctu_mutex_group = ctu.add_mutually_exclusive_group()
380*a9ac8606Spatrick        ctu_mutex_group.add_argument(
381*a9ac8606Spatrick            '--ctu',
382*a9ac8606Spatrick            action='store_const',
383*a9ac8606Spatrick            const=CtuConfig(collect=True, analyze=True,
384*a9ac8606Spatrick                            dir='', extdef_map_cmd=''),
385*a9ac8606Spatrick            dest='ctu_phases',
386*a9ac8606Spatrick            help="""Perform cross translation unit (ctu) analysis (both collect
387*a9ac8606Spatrick            and analyze phases) using default <ctu-dir> for temporary output.
388*a9ac8606Spatrick            At the end of the analysis, the temporary directory is removed.""")
389*a9ac8606Spatrick        ctu.add_argument(
390*a9ac8606Spatrick            '--ctu-dir',
391*a9ac8606Spatrick            metavar='<ctu-dir>',
392*a9ac8606Spatrick            dest='ctu_dir',
393*a9ac8606Spatrick            default='ctu-dir',
394*a9ac8606Spatrick            help="""Defines the temporary directory used between ctu
395*a9ac8606Spatrick            phases.""")
396*a9ac8606Spatrick        ctu_mutex_group.add_argument(
397*a9ac8606Spatrick            '--ctu-collect-only',
398*a9ac8606Spatrick            action='store_const',
399*a9ac8606Spatrick            const=CtuConfig(collect=True, analyze=False,
400*a9ac8606Spatrick                            dir='', extdef_map_cmd=''),
401*a9ac8606Spatrick            dest='ctu_phases',
402*a9ac8606Spatrick            help="""Perform only the collect phase of ctu.
403*a9ac8606Spatrick            Keep <ctu-dir> for further use.""")
404*a9ac8606Spatrick        ctu_mutex_group.add_argument(
405*a9ac8606Spatrick            '--ctu-analyze-only',
406*a9ac8606Spatrick            action='store_const',
407*a9ac8606Spatrick            const=CtuConfig(collect=False, analyze=True,
408*a9ac8606Spatrick                            dir='', extdef_map_cmd=''),
409*a9ac8606Spatrick            dest='ctu_phases',
410*a9ac8606Spatrick            help="""Perform only the analyze phase of ctu. <ctu-dir> should be
411*a9ac8606Spatrick            present and will not be removed after analysis.""")
412*a9ac8606Spatrick        ctu.add_argument(
413*a9ac8606Spatrick            '--use-extdef-map-cmd',
414*a9ac8606Spatrick            metavar='<path>',
415*a9ac8606Spatrick            dest='extdef_map_cmd',
416*a9ac8606Spatrick            default='clang-extdef-mapping',
417*a9ac8606Spatrick            help="""'%(prog)s' uses the 'clang-extdef-mapping' executable
418*a9ac8606Spatrick            relative to itself for generating external definition maps for
419*a9ac8606Spatrick            static analysis. One can override this behavior with this option
420*a9ac8606Spatrick            by using the 'clang-extdef-mapping' packaged with Xcode (on OS X)
421*a9ac8606Spatrick            or from the PATH.""")
422*a9ac8606Spatrick    return parser
423*a9ac8606Spatrick
424*a9ac8606Spatrick
425*a9ac8606Spatrickdef create_default_parser():
426*a9ac8606Spatrick    """ Creates command line parser for all build wrapper commands. """
427*a9ac8606Spatrick
428*a9ac8606Spatrick    parser = argparse.ArgumentParser(
429*a9ac8606Spatrick        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
430*a9ac8606Spatrick
431*a9ac8606Spatrick    parser.add_argument(
432*a9ac8606Spatrick        '--verbose',
433*a9ac8606Spatrick        '-v',
434*a9ac8606Spatrick        action='count',
435*a9ac8606Spatrick        default=0,
436*a9ac8606Spatrick        help="""Enable verbose output from '%(prog)s'. A second, third and
437*a9ac8606Spatrick        fourth flags increases verbosity.""")
438*a9ac8606Spatrick    return parser
439*a9ac8606Spatrick
440*a9ac8606Spatrick
441*a9ac8606Spatrickdef parser_add_cdb(parser):
442*a9ac8606Spatrick    parser.add_argument(
443*a9ac8606Spatrick        '--cdb',
444*a9ac8606Spatrick        metavar='<file>',
445*a9ac8606Spatrick        default="compile_commands.json",
446*a9ac8606Spatrick        help="""The JSON compilation database.""")
447*a9ac8606Spatrick
448*a9ac8606Spatrick
449*a9ac8606Spatrickdef parser_add_prefer_wrapper(parser):
450*a9ac8606Spatrick    parser.add_argument(
451*a9ac8606Spatrick        '--override-compiler',
452*a9ac8606Spatrick        action='store_true',
453*a9ac8606Spatrick        help="""Always resort to the compiler wrapper even when better
454*a9ac8606Spatrick        intercept methods are available.""")
455*a9ac8606Spatrick
456*a9ac8606Spatrick
457*a9ac8606Spatrickdef parser_add_compilers(parser):
458*a9ac8606Spatrick    parser.add_argument(
459*a9ac8606Spatrick        '--use-cc',
460*a9ac8606Spatrick        metavar='<path>',
461*a9ac8606Spatrick        dest='cc',
462*a9ac8606Spatrick        default=os.getenv('CC', 'cc'),
463*a9ac8606Spatrick        help="""When '%(prog)s' analyzes a project by interposing a compiler
464*a9ac8606Spatrick        wrapper, which executes a real compiler for compilation and do other
465*a9ac8606Spatrick        tasks (record the compiler invocation). Because of this interposing,
466*a9ac8606Spatrick        '%(prog)s' does not know what compiler your project normally uses.
467*a9ac8606Spatrick        Instead, it simply overrides the CC environment variable, and guesses
468*a9ac8606Spatrick        your default compiler.
469*a9ac8606Spatrick
470*a9ac8606Spatrick        If you need '%(prog)s' to use a specific compiler for *compilation*
471*a9ac8606Spatrick        then you can use this option to specify a path to that compiler.""")
472*a9ac8606Spatrick    parser.add_argument(
473*a9ac8606Spatrick        '--use-c++',
474*a9ac8606Spatrick        metavar='<path>',
475*a9ac8606Spatrick        dest='cxx',
476*a9ac8606Spatrick        default=os.getenv('CXX', 'c++'),
477*a9ac8606Spatrick        help="""This is the same as "--use-cc" but for C++ code.""")
478*a9ac8606Spatrick
479*a9ac8606Spatrick
480*a9ac8606Spatrickclass AppendCommaSeparated(argparse.Action):
481*a9ac8606Spatrick    """ argparse Action class to support multiple comma separated lists. """
482*a9ac8606Spatrick
483*a9ac8606Spatrick    def __call__(self, __parser, namespace, values, __option_string):
484*a9ac8606Spatrick        # getattr(obj, attr, default) does not really returns default but none
485*a9ac8606Spatrick        if getattr(namespace, self.dest, None) is None:
486*a9ac8606Spatrick            setattr(namespace, self.dest, [])
487*a9ac8606Spatrick        # once it's fixed we can use as expected
488*a9ac8606Spatrick        actual = getattr(namespace, self.dest)
489*a9ac8606Spatrick        actual.extend(values.split(','))
490*a9ac8606Spatrick        setattr(namespace, self.dest, actual)
491*a9ac8606Spatrick
492*a9ac8606Spatrick
493*a9ac8606Spatrickdef print_active_checkers(checkers):
494*a9ac8606Spatrick    """ Print active checkers to stdout. """
495*a9ac8606Spatrick
496*a9ac8606Spatrick    for name in sorted(name for name, (_, active) in checkers.items()
497*a9ac8606Spatrick                       if active):
498*a9ac8606Spatrick        print(name)
499*a9ac8606Spatrick
500*a9ac8606Spatrick
501*a9ac8606Spatrickdef print_checkers(checkers):
502*a9ac8606Spatrick    """ Print verbose checker help to stdout. """
503*a9ac8606Spatrick
504*a9ac8606Spatrick    print('')
505*a9ac8606Spatrick    print('available checkers:')
506*a9ac8606Spatrick    print('')
507*a9ac8606Spatrick    for name in sorted(checkers.keys()):
508*a9ac8606Spatrick        description, active = checkers[name]
509*a9ac8606Spatrick        prefix = '+' if active else ' '
510*a9ac8606Spatrick        if len(name) > 30:
511*a9ac8606Spatrick            print(' {0} {1}'.format(prefix, name))
512*a9ac8606Spatrick            print(' ' * 35 + description)
513*a9ac8606Spatrick        else:
514*a9ac8606Spatrick            print(' {0} {1: <30}  {2}'.format(prefix, name, description))
515*a9ac8606Spatrick    print('')
516*a9ac8606Spatrick    print('NOTE: "+" indicates that an analysis is enabled by default.')
517*a9ac8606Spatrick    print('')
518