Source code for m2isar.warnings

import argparse
from dataclasses import dataclass, field
from typing import Set

[docs] KNOWN_WARNINGS = { 'implicit-trunc', 'shift-overflow', 'shift-signed', 'implicit-extend', 'sign-compare', 'unused-value', 'bit-op-missmatch', }
@dataclass
[docs] class WarningsInfo: # known: Set[str] = field(default_factory=set)
[docs] known: Set[str] = field(default_factory=lambda: set(KNOWN_WARNINGS))
# defaults: Set[str] = field(default_factory=set)
[docs] defaults: Set[str] = field(default_factory=lambda: set(KNOWN_WARNINGS))
[docs] enabled: Set[str] = field(default_factory=set)
[docs] disabled: Set[str] = field(default_factory=set)
[docs] as_error: Set[str] = field(default_factory=set)
[docs] all_as_error: bool = False
@property
[docs] def warnings(self): return (self.defaults - self.disabled) | self.enabled
@property
[docs] def errors(self): return self.as_error if not self.all_as_error else self.warnings
[docs] class WarningFlagAction(argparse.Action):
[docs] def __call__(self, parser, namespace, values, option_string=None): warnings_info = getattr(namespace, 'warnings', None) if warnings_info is None: warnings_info = WarningsInfo() for val in values: if val == 'no-error': warnings_info.all_as_error = False elif val.startswith('no-'): warn = val[3:] assert warn in warnings_info.known, f"Unknown warning: {warn}" warnings_info.disabled.add(warn) elif val.startswith('error='): warn = val[6:] assert warn in warnings_info.known, f"Unknown warning: {warn}" warnings_info.as_error.add(warn) elif val == 'error': warnings_info.all_as_error = True elif val == 'all': warnings_info.enabled.update(warnings_info.known) else: warn = val[3:] assert warn in warnings_info.known, f"Unknown warning: {val}" warnings_info.enabled.add(val) # No need for -Wall as all warnings are enabled by default setattr(namespace, 'warnings', warnings_info)
[docs] def add_warnings_flags(parser, known_warnings: Set[str], default_warnings: Set[str]): parser.add_argument( '-W', dest='warnings', metavar='warning', action=WarningFlagAction, nargs='+', help=( "Enable/disable warnings like -Wfoo or -Wno-foo; " "Make fatal with -Werror or -Werror=foo" ), ) # Defaults warnings_info = WarningsInfo(known=known_warnings, defaults=default_warnings) parser.set_defaults(warnings=warnings_info)
[docs] class WarningsManager: def __init__(self, warnings_info: WarningsInfo):
[docs] self.warnings_info = warnings_info
# TODO: warnings as errors?
[docs] def emit_warning(self, msg, name=None, logger=None, line_info=None): log_warn_f = logging.warning if logger is None else logger.warning log_err_f = logging.error if logger is None else logger.error if self.warnings_info is None: return # ignore assert name in self.warnings_info.known, f"Unknown warning: {name}" is_err = name in self.warnings_info.errors if name not in self.warnings_info.warnings: # do nothing return log_f = log_err_f if is_err else log_warn_f if name is not None: msg += f" [-W{name}]" if line_info is not None: line_info_str = f"{line_info.file_path}:{line_info.start_line_no}" msg += f" @ {line_info_str}" log_f(msg) if is_err: raise RuntimeError(msg)