blob: ab422066cab128f5fc0ac57c913d058b4f3bb2c9 [file] [log] [blame]
Laszlo Nagybc687582016-01-12 22:38:41 +00001# -*- coding: utf-8 -*-
2# The LLVM Compiler Infrastructure
3#
4# This file is distributed under the University of Illinois Open Source
5# License. See LICENSE.TXT for details.
6""" This module is responsible for the Clang executable.
7
8Since Clang command line interface is so rich, but this project is using only
9a subset of that, it makes sense to create a function specific wrapper. """
10
Ilya Biryukov8b9b3bd2018-03-01 14:54:16 +000011import subprocess
Laszlo Nagybc687582016-01-12 22:38:41 +000012import re
Laszlo Nagy46fc18a2017-01-28 22:48:26 +000013from libscanbuild import run_command
Laszlo Nagybc687582016-01-12 22:38:41 +000014from libscanbuild.shell import decode
15
Ilya Biryukov8b9b3bd2018-03-01 14:54:16 +000016__all__ = ['get_version', 'get_arguments', 'get_checkers', 'is_ctu_capable',
17 'get_triple_arch']
Laszlo Nagybc687582016-01-12 22:38:41 +000018
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000019# regex for activated checker
20ACTIVE_CHECKER_PATTERN = re.compile(r'^-analyzer-checker=(.*)$')
Laszlo Nagybc687582016-01-12 22:38:41 +000021
Laszlo Nagybc687582016-01-12 22:38:41 +000022
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000023def get_version(clang):
24 """ Returns the compiler version as string.
25
26 :param clang: the compiler we are using
27 :return: the version string printed to stderr """
28
Laszlo Nagy46fc18a2017-01-28 22:48:26 +000029 output = run_command([clang, '-v'])
30 # the relevant version info is in the first line
31 return output[0]
Laszlo Nagybc687582016-01-12 22:38:41 +000032
33
34def get_arguments(command, cwd):
35 """ Capture Clang invocation.
36
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000037 :param command: the compilation command
38 :param cwd: the current working directory
39 :return: the detailed front-end invocation command """
Laszlo Nagybc687582016-01-12 22:38:41 +000040
41 cmd = command[:]
42 cmd.insert(1, '-###')
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000043
Laszlo Nagy46fc18a2017-01-28 22:48:26 +000044 output = run_command(cmd, cwd=cwd)
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000045 # The relevant information is in the last line of the output.
46 # Don't check if finding last line fails, would throw exception anyway.
Laszlo Nagy46fc18a2017-01-28 22:48:26 +000047 last_line = output[-1]
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000048 if re.search(r'clang(.*): error:', last_line):
49 raise Exception(last_line)
50 return decode(last_line)
Laszlo Nagybc687582016-01-12 22:38:41 +000051
52
53def get_active_checkers(clang, plugins):
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000054 """ Get the active checker list.
Laszlo Nagybc687582016-01-12 22:38:41 +000055
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000056 :param clang: the compiler we are using
57 :param plugins: list of plugins which was requested by the user
58 :return: list of checker names which are active
Laszlo Nagybc687582016-01-12 22:38:41 +000059
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000060 To get the default checkers we execute Clang to print how this
61 compilation would be called. And take out the enabled checker from the
62 arguments. For input file we specify stdin and pass only language
63 information. """
64
65 def get_active_checkers_for(language):
Laszlo Nagybc687582016-01-12 22:38:41 +000066 """ Returns a list of active checkers for the given language. """
67
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000068 load_args = [arg
69 for plugin in plugins
70 for arg in ['-Xclang', '-load', '-Xclang', plugin]]
71 cmd = [clang, '--analyze'] + load_args + ['-x', language, '-']
72 return [ACTIVE_CHECKER_PATTERN.match(arg).group(1)
73 for arg in get_arguments(cmd, '.')
74 if ACTIVE_CHECKER_PATTERN.match(arg)]
Laszlo Nagybc687582016-01-12 22:38:41 +000075
76 result = set()
77 for language in ['c', 'c++', 'objective-c', 'objective-c++']:
Laszlo Nagy4f6a1752016-09-24 00:20:59 +000078 result.update(get_active_checkers_for(language))
79 return frozenset(result)
80
81
82def is_active(checkers):
83 """ Returns a method, which classifies the checker active or not,
84 based on the received checker name list. """
85
86 def predicate(checker):
87 """ Returns True if the given checker is active. """
88
89 return any(pattern.match(checker) for pattern in predicate.patterns)
90
91 predicate.patterns = [re.compile(r'^' + a + r'(\.|$)') for a in checkers]
92 return predicate
93
94
95def parse_checkers(stream):
96 """ Parse clang -analyzer-checker-help output.
97
98 Below the line 'CHECKERS:' are there the name description pairs.
99 Many of them are in one line, but some long named checker has the
100 name and the description in separate lines.
101
102 The checker name is always prefixed with two space character. The
103 name contains no whitespaces. Then followed by newline (if it's
104 too long) or other space characters comes the description of the
105 checker. The description ends with a newline character.
106
107 :param stream: list of lines to parse
108 :return: generator of tuples
109
110 (<checker name>, <checker description>) """
111
112 lines = iter(stream)
113 # find checkers header
114 for line in lines:
115 if re.match(r'^CHECKERS:', line):
116 break
117 # find entries
118 state = None
119 for line in lines:
120 if state and not re.match(r'^\s\s\S', line):
121 yield (state, line.strip())
122 state = None
123 elif re.match(r'^\s\s\S+$', line.rstrip()):
124 state = line.strip()
125 else:
126 pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
127 match = pattern.match(line.rstrip())
128 if match:
129 current = match.groupdict()
130 yield (current['key'], current['value'])
Laszlo Nagybc687582016-01-12 22:38:41 +0000131
132
133def get_checkers(clang, plugins):
134 """ Get all the available checkers from default and from the plugins.
135
Laszlo Nagy4f6a1752016-09-24 00:20:59 +0000136 :param clang: the compiler we are using
137 :param plugins: list of plugins which was requested by the user
138 :return: a dictionary of all available checkers and its status
Laszlo Nagybc687582016-01-12 22:38:41 +0000139
Laszlo Nagy4f6a1752016-09-24 00:20:59 +0000140 {<checker name>: (<checker description>, <is active by default>)} """
Laszlo Nagybc687582016-01-12 22:38:41 +0000141
142 load = [elem for plugin in plugins for elem in ['-load', plugin]]
143 cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
144
Laszlo Nagy46fc18a2017-01-28 22:48:26 +0000145 lines = run_command(cmd)
Laszlo Nagy4f6a1752016-09-24 00:20:59 +0000146
147 is_active_checker = is_active(get_active_checkers(clang, plugins))
148
Laszlo Nagybc687582016-01-12 22:38:41 +0000149 checkers = {
Laszlo Nagy4f6a1752016-09-24 00:20:59 +0000150 name: (description, is_active_checker(name))
151 for name, description in parse_checkers(lines)
Laszlo Nagybc687582016-01-12 22:38:41 +0000152 }
Laszlo Nagy4f6a1752016-09-24 00:20:59 +0000153 if not checkers:
Laszlo Nagybc687582016-01-12 22:38:41 +0000154 raise Exception('Could not query Clang for available checkers.')
Laszlo Nagy4f6a1752016-09-24 00:20:59 +0000155
156 return checkers
Ilya Biryukov8b9b3bd2018-03-01 14:54:16 +0000157
158
159def is_ctu_capable(func_map_cmd):
160 """ Detects if the current (or given) clang and function mapping
161 executables are CTU compatible. """
162
163 try:
164 run_command([func_map_cmd, '-version'])
165 except (OSError, subprocess.CalledProcessError):
166 return False
167 return True
168
169
170def get_triple_arch(command, cwd):
171 """Returns the architecture part of the target triple for the given
172 compilation command. """
173
174 cmd = get_arguments(command, cwd)
175 try:
176 separator = cmd.index("-triple")
177 return cmd[separator + 1]
178 except (IndexError, ValueError):
179 return ""