Clang Project

clang_source_code/tools/scan-build-py/libscanbuild/clang.py
1# -*- coding: utf-8 -*-
2# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3# See https://llvm.org/LICENSE.txt for license information.
4# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5""" This module is responsible for the Clang executable.
6
7Since Clang command line interface is so rich, but this project is using only
8a subset of that, it makes sense to create a function specific wrapper. """
9
10import subprocess
11import re
12from libscanbuild import run_command
13from libscanbuild.shell import decode
14
15__all__ = ['get_version', 'get_arguments', 'get_checkers', 'is_ctu_capable',
16           'get_triple_arch']
17
18# regex for activated checker
19ACTIVE_CHECKER_PATTERN = re.compile(r'^-analyzer-checker=(.*)$')
20
21
22def get_version(clang):
23    """ Returns the compiler version as string.
24
25    :param clang:   the compiler we are using
26    :return:        the version string printed to stderr """
27
28    output = run_command([clang, '-v'])
29    # the relevant version info is in the first line
30    return output[0]
31
32
33def get_arguments(command, cwd):
34    """ Capture Clang invocation.
35
36    :param command: the compilation command
37    :param cwd:     the current working directory
38    :return:        the detailed front-end invocation command """
39
40    cmd = command[:]
41    cmd.insert(1, '-###')
42
43    output = run_command(cmd, cwd=cwd)
44    # The relevant information is in the last line of the output.
45    # Don't check if finding last line fails, would throw exception anyway.
46    last_line = output[-1]
47    if re.search(r'clang(.*): error:', last_line):
48        raise Exception(last_line)
49    return decode(last_line)
50
51
52def get_active_checkers(clang, plugins):
53    """ Get the active checker list.
54
55    :param clang:   the compiler we are using
56    :param plugins: list of plugins which was requested by the user
57    :return:        list of checker names which are active
58
59    To get the default checkers we execute Clang to print how this
60    compilation would be called. And take out the enabled checker from the
61    arguments. For input file we specify stdin and pass only language
62    information. """
63
64    def get_active_checkers_for(language):
65        """ Returns a list of active checkers for the given language. """
66
67        load_args = [arg
68                     for plugin in plugins
69                     for arg in ['-Xclang', '-load', '-Xclang', plugin]]
70        cmd = [clang, '--analyze'] + load_args + ['-x', language, '-']
71        return [ACTIVE_CHECKER_PATTERN.match(arg).group(1)
72                for arg in get_arguments(cmd, '.')
73                if ACTIVE_CHECKER_PATTERN.match(arg)]
74
75    result = set()
76    for language in ['c', 'c++', 'objective-c', 'objective-c++']:
77        result.update(get_active_checkers_for(language))
78    return frozenset(result)
79
80
81def is_active(checkers):
82    """ Returns a method, which classifies the checker active or not,
83    based on the received checker name list. """
84
85    def predicate(checker):
86        """ Returns True if the given checker is active. """
87
88        return any(pattern.match(checker) for pattern in predicate.patterns)
89
90    predicate.patterns = [re.compile(r'^' + a + r'(\.|$)') for a in checkers]
91    return predicate
92
93
94def parse_checkers(stream):
95    """ Parse clang -analyzer-checker-help output.
96
97    Below the line 'CHECKERS:' are there the name description pairs.
98    Many of them are in one line, but some long named checker has the
99    name and the description in separate lines.
100
101    The checker name is always prefixed with two space character. The
102    name contains no whitespaces. Then followed by newline (if it's
103    too long) or other space characters comes the description of the
104    checker. The description ends with a newline character.
105
106    :param stream:  list of lines to parse
107    :return:        generator of tuples
108
109    (<checker name>, <checker description>) """
110
111    lines = iter(stream)
112    # find checkers header
113    for line in lines:
114        if re.match(r'^CHECKERS:', line):
115            break
116    # find entries
117    state = None
118    for line in lines:
119        if state and not re.match(r'^\s\s\S', line):
120            yield (state, line.strip())
121            state = None
122        elif re.match(r'^\s\s\S+$', line.rstrip()):
123            state = line.strip()
124        else:
125            pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
126            match = pattern.match(line.rstrip())
127            if match:
128                current = match.groupdict()
129                yield (current['key'], current['value'])
130
131
132def get_checkers(clang, plugins):
133    """ Get all the available checkers from default and from the plugins.
134
135    :param clang:   the compiler we are using
136    :param plugins: list of plugins which was requested by the user
137    :return:        a dictionary of all available checkers and its status
138
139    {<checker name>: (<checker description>, <is active by default>)} """
140
141    load = [elem for plugin in plugins for elem in ['-load', plugin]]
142    cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
143
144    lines = run_command(cmd)
145
146    is_active_checker = is_active(get_active_checkers(clang, plugins))
147
148    checkers = {
149        name: (description, is_active_checker(name))
150        for name, description in parse_checkers(lines)
151    }
152    if not checkers:
153        raise Exception('Could not query Clang for available checkers.')
154
155    return checkers
156
157
158def is_ctu_capable(extdef_map_cmd):
159    """ Detects if the current (or given) clang and external definition mapping
160    executables are CTU compatible. """
161
162    try:
163        run_command([extdef_map_cmd, '-version'])
164    except (OSError, subprocess.CalledProcessError):
165        return False
166    return True
167
168
169def get_triple_arch(command, cwd):
170    """Returns the architecture part of the target triple for the given
171    compilation command. """
172
173    cmd = get_arguments(command, cwd)
174    try:
175        separator = cmd.index("-triple")
176        return cmd[separator + 1]
177    except (IndexError, ValueError):
178        return ""
179