diff options
Diffstat (limited to 'tools/scan-build-py/libscanbuild/command.py')
-rw-r--r-- | tools/scan-build-py/libscanbuild/command.py | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/tools/scan-build-py/libscanbuild/command.py b/tools/scan-build-py/libscanbuild/command.py new file mode 100644 index 0000000000..69ca3393f9 --- /dev/null +++ b/tools/scan-build-py/libscanbuild/command.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +""" This module is responsible for to parse a compiler invocation. """ + +import re +import os + +__all__ = ['Action', 'classify_parameters', 'classify_source'] + + +class Action(object): + """ Enumeration class for compiler action. """ + + Link, Compile, Ignored = range(3) + + +def classify_parameters(command): + """ Parses the command line arguments of the given invocation. """ + + # result value of this method. + # some value are preset, some will be set only when found. + result = { + 'action': Action.Link, + 'files': [], + 'output': None, + 'compile_options': [], + 'c++': is_cplusplus_compiler(command[0]) + # archs_seen + # language + } + + # data structure to ignore compiler parameters. + # key: parameter name, value: number of parameters to ignore afterwards. + ignored = { + '-g': 0, + '-fsyntax-only': 0, + '-save-temps': 0, + '-install_name': 1, + '-exported_symbols_list': 1, + '-current_version': 1, + '-compatibility_version': 1, + '-init': 1, + '-e': 1, + '-seg1addr': 1, + '-bundle_loader': 1, + '-multiply_defined': 1, + '-sectorder': 3, + '--param': 1, + '--serialize-diagnostics': 1 + } + + args = iter(command[1:]) + for arg in args: + # compiler action parameters are the most important ones... + if arg in {'-E', '-S', '-cc1', '-M', '-MM', '-###'}: + result.update({'action': Action.Ignored}) + elif arg == '-c': + result.update({'action': max(result['action'], Action.Compile)}) + # arch flags are taken... + elif arg == '-arch': + archs = result.get('archs_seen', []) + result.update({'archs_seen': archs + [next(args)]}) + # explicit language option taken... + elif arg == '-x': + result.update({'language': next(args)}) + # output flag taken... + elif arg == '-o': + result.update({'output': next(args)}) + # warning disable options are taken... + elif re.match(r'^-Wno-', arg): + result['compile_options'].append(arg) + # warning options are ignored... + elif re.match(r'^-[mW].+', arg): + pass + # some preprocessor parameters are ignored... + elif arg in {'-MD', '-MMD', '-MG', '-MP'}: + pass + elif arg in {'-MF', '-MT', '-MQ'}: + next(args) + # linker options are ignored... + elif arg in {'-static', '-shared', '-s', '-rdynamic'} or \ + re.match(r'^-[lL].+', arg): + pass + elif arg in {'-l', '-L', '-u', '-z', '-T', '-Xlinker'}: + next(args) + # some other options are ignored... + elif arg in ignored.keys(): + for _ in range(ignored[arg]): + next(args) + # parameters which looks source file are taken... + elif re.match(r'^[^-].+', arg) and classify_source(arg): + result['files'].append(arg) + # and consider everything else as compile option. + else: + result['compile_options'].append(arg) + + return result + + +def classify_source(filename, cplusplus=False): + """ Return the language from file name extension. """ + + mapping = { + '.c': 'c++' if cplusplus else 'c', + '.i': 'c++-cpp-output' if cplusplus else 'c-cpp-output', + '.ii': 'c++-cpp-output', + '.m': 'objective-c', + '.mi': 'objective-c-cpp-output', + '.mm': 'objective-c++', + '.mii': 'objective-c++-cpp-output', + '.C': 'c++', + '.cc': 'c++', + '.CC': 'c++', + '.cp': 'c++', + '.cpp': 'c++', + '.cxx': 'c++', + '.c++': 'c++', + '.C++': 'c++', + '.txx': 'c++' + } + + __, extension = os.path.splitext(os.path.basename(filename)) + return mapping.get(extension) + + +def is_cplusplus_compiler(name): + """ Returns true when the compiler name refer to a C++ compiler. """ + + match = re.match(r'^([^/]*/)*(\w*-)*(\w+\+\+)(-(\d+(\.\d+){0,3}))?$', name) + return False if match is None else True |