import subprocess
import re
from libscanbuild import run_command
from libscanbuild.shell import decode
__all__ = ['get_version', 'get_arguments', 'get_checkers', 'is_ctu_capable',
'get_triple_arch']
ACTIVE_CHECKER_PATTERN = re.compile(r'^-analyzer-checker=(.*)$')
class ClangErrorException(Exception):
def __init__(self, error):
self.error = error
def get_version(clang):
output = run_command([clang, '-v'])
return output[0]
def get_arguments(command, cwd):
cmd = command[:]
cmd.insert(1, '-###')
cmd.append('-fno-color-diagnostics')
output = run_command(cmd, cwd=cwd)
last_line = output[-1]
if re.search(r'clang(.*): error:', last_line):
raise ClangErrorException(last_line)
return decode(last_line)
def get_active_checkers(clang, plugins):
def get_active_checkers_for(language):
load_args = [arg
for plugin in plugins
for arg in ['-Xclang', '-load', '-Xclang', plugin]]
cmd = [clang, '--analyze'] + load_args + ['-x', language, '-']
return [ACTIVE_CHECKER_PATTERN.match(arg).group(1)
for arg in get_arguments(cmd, '.')
if ACTIVE_CHECKER_PATTERN.match(arg)]
result = set()
for language in ['c', 'c++', 'objective-c', 'objective-c++']:
result.update(get_active_checkers_for(language))
return frozenset(result)
def is_active(checkers):
def predicate(checker):
return any(pattern.match(checker) for pattern in predicate.patterns)
predicate.patterns = [re.compile(r'^' + a + r'(\.|$)') for a in checkers]
return predicate
def parse_checkers(stream):
lines = iter(stream)
for line in lines:
if re.match(r'^CHECKERS:', line):
break
state = None
for line in lines:
if state and not re.match(r'^\s\s\S', line):
yield (state, line.strip())
state = None
elif re.match(r'^\s\s\S+$', line.rstrip()):
state = line.strip()
else:
pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
match = pattern.match(line.rstrip())
if match:
current = match.groupdict()
yield (current['key'], current['value'])
def get_checkers(clang, plugins):
load = [elem for plugin in plugins for elem in ['-load', plugin]]
cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
lines = run_command(cmd)
is_active_checker = is_active(get_active_checkers(clang, plugins))
checkers = {
name: (description, is_active_checker(name))
for name, description in parse_checkers(lines)
}
if not checkers:
raise Exception('Could not query Clang for available checkers.')
return checkers
def is_ctu_capable(extdef_map_cmd):
try:
run_command([extdef_map_cmd, '-version'])
except (OSError, subprocess.CalledProcessError):
return False
return True
def get_triple_arch(command, cwd):
cmd = get_arguments(command, cwd)
try:
separator = cmd.index("-triple")
return cmd[separator + 1]
except (IndexError, ValueError):
return ""