Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / tools / scan-build-py / lib / libscanbuild / clang.py
blob25a50b6a216dc096363ab5cd357228990e71ccf3
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.
7 Since Clang command line interface is so rich, but this project is using only
8 a subset of that, it makes sense to create a function specific wrapper. """
10 import subprocess
11 import re
12 from libscanbuild import run_command
13 from libscanbuild.shell import decode
15 __all__ = [
16 "get_version",
17 "get_arguments",
18 "get_checkers",
19 "is_ctu_capable",
20 "get_triple_arch",
23 # regex for activated checker
24 ACTIVE_CHECKER_PATTERN = re.compile(r"^-analyzer-checker=(.*)$")
27 class ClangErrorException(Exception):
28 def __init__(self, error):
29 self.error = error
32 def get_version(clang):
33 """Returns the compiler version as string.
35 :param clang: the compiler we are using
36 :return: the version string printed to stderr"""
38 output = run_command([clang, "-v"])
39 # the relevant version info is in the first line
40 return output[0]
43 def get_arguments(command, cwd):
44 """Capture Clang invocation.
46 :param command: the compilation command
47 :param cwd: the current working directory
48 :return: the detailed front-end invocation command"""
50 cmd = command[:]
51 cmd.insert(1, "-###")
52 cmd.append("-fno-color-diagnostics")
54 output = run_command(cmd, cwd=cwd)
55 # The relevant information is in the last line of the output.
56 # Don't check if finding last line fails, would throw exception anyway.
57 last_line = output[-1]
58 if re.search(r"clang(.*): error:", last_line):
59 raise ClangErrorException(last_line)
60 return decode(last_line)
63 def get_active_checkers(clang, plugins):
64 """Get the active checker list.
66 :param clang: the compiler we are using
67 :param plugins: list of plugins which was requested by the user
68 :return: list of checker names which are active
70 To get the default checkers we execute Clang to print how this
71 compilation would be called. And take out the enabled checker from the
72 arguments. For input file we specify stdin and pass only language
73 information."""
75 def get_active_checkers_for(language):
76 """Returns a list of active checkers for the given language."""
78 load_args = [
79 arg for plugin in plugins for arg in ["-Xclang", "-load", "-Xclang", plugin]
81 cmd = [clang, "--analyze"] + load_args + ["-x", language, "-"]
82 return [
83 ACTIVE_CHECKER_PATTERN.match(arg).group(1)
84 for arg in get_arguments(cmd, ".")
85 if ACTIVE_CHECKER_PATTERN.match(arg)
88 result = set()
89 for language in ["c", "c++", "objective-c", "objective-c++"]:
90 result.update(get_active_checkers_for(language))
91 return frozenset(result)
94 def is_active(checkers):
95 """Returns a method, which classifies the checker active or not,
96 based on the received checker name list."""
98 def predicate(checker):
99 """Returns True if the given checker is active."""
101 return any(pattern.match(checker) for pattern in predicate.patterns)
103 predicate.patterns = [re.compile(r"^" + a + r"(\.|$)") for a in checkers]
104 return predicate
107 def parse_checkers(stream):
108 """Parse clang -analyzer-checker-help output.
110 Below the line 'CHECKERS:' are there the name description pairs.
111 Many of them are in one line, but some long named checker has the
112 name and the description in separate lines.
114 The checker name is always prefixed with two space character. The
115 name contains no whitespaces. Then followed by newline (if it's
116 too long) or other space characters comes the description of the
117 checker. The description ends with a newline character.
119 :param stream: list of lines to parse
120 :return: generator of tuples
122 (<checker name>, <checker description>)"""
124 lines = iter(stream)
125 # find checkers header
126 for line in lines:
127 if re.match(r"^CHECKERS:", line):
128 break
129 # find entries
130 state = None
131 for line in lines:
132 if state and not re.match(r"^\s\s\S", line):
133 yield (state, line.strip())
134 state = None
135 elif re.match(r"^\s\s\S+$", line.rstrip()):
136 state = line.strip()
137 else:
138 pattern = re.compile(r"^\s\s(?P<key>\S*)\s*(?P<value>.*)")
139 match = pattern.match(line.rstrip())
140 if match:
141 current = match.groupdict()
142 yield (current["key"], current["value"])
145 def get_checkers(clang, plugins):
146 """Get all the available checkers from default and from the plugins.
148 :param clang: the compiler we are using
149 :param plugins: list of plugins which was requested by the user
150 :return: a dictionary of all available checkers and its status
152 {<checker name>: (<checker description>, <is active by default>)}"""
154 load = [elem for plugin in plugins for elem in ["-load", plugin]]
155 cmd = [clang, "-cc1"] + load + ["-analyzer-checker-help"]
157 lines = run_command(cmd)
159 is_active_checker = is_active(get_active_checkers(clang, plugins))
161 checkers = {
162 name: (description, is_active_checker(name))
163 for name, description in parse_checkers(lines)
165 if not checkers:
166 raise Exception("Could not query Clang for available checkers.")
168 return checkers
171 def is_ctu_capable(extdef_map_cmd):
172 """Detects if the current (or given) clang and external definition mapping
173 executables are CTU compatible."""
175 try:
176 run_command([extdef_map_cmd, "-version"])
177 except (OSError, subprocess.CalledProcessError):
178 return False
179 return True
182 def get_triple_arch(command, cwd):
183 """Returns the architecture part of the target triple for the given
184 compilation command."""
186 cmd = get_arguments(command, cwd)
187 try:
188 separator = cmd.index("-triple")
189 return cmd[separator + 1]
190 except (IndexError, ValueError):
191 return ""