diff --git a/amaranth/_unused.py b/amaranth/_unused.py index 4f2507bc1..dbb9b0c33 100644 --- a/amaranth/_unused.py +++ b/amaranth/_unused.py @@ -1,7 +1,7 @@ import sys import warnings -from ._utils import get_linter_option +from ._utils import get_linter_option, collate_linter_options __all__ = ["UnusedMustUse", "MustUse"] @@ -18,7 +18,9 @@ class MustUse: def __new__(cls, *args, src_loc_at=0, **kwargs): frame = sys._getframe(1 + src_loc_at) self = super().__new__(cls) - self._MustUse__used = False + + self._MustUse__used = False + self._MustUse__options = collate_linter_options(frame) self._MustUse__context = dict( filename=frame.f_code.co_filename, lineno=frame.f_lineno, @@ -31,7 +33,7 @@ def __del__(self): if getattr(self._MustUse__warning, "_MustUse__silence", False): return if hasattr(self, "_MustUse__used") and not self._MustUse__used: - if get_linter_option(self._MustUse__context["filename"], + if get_linter_option(self._MustUse__options, self._MustUse__warning.__qualname__, bool, True): warnings.warn_explicit( f"{self!r} created but never used", self._MustUse__warning, diff --git a/amaranth/_utils.py b/amaranth/_utils.py index b6591fdbb..f728e5153 100644 --- a/amaranth/_utils.py +++ b/amaranth/_utils.py @@ -75,6 +75,7 @@ def decorator_like(*args, **kwargs): return decorator_like + def get_linter_options(filename): first_line = linecache.getline(filename, 1) if first_line: @@ -84,8 +85,33 @@ def get_linter_options(filename): return dict() -def get_linter_option(filename, name, type, default): - options = get_linter_options(filename) +def collate_linter_options(frame): + """ + Get all linter options for a given stack frame. This iterates down the frames, collating options of the form: + + .. code:: + # amaranth: {name}=value + + The earliest option value in the stack takes precedence + + Returns + ------- + :class:`bool` or :class:`int` + Option value + """ + + options = {} + while frame: + f_opts = get_linter_options(frame.f_code.co_filename) + options = f_opts | options + if frame.f_back is None: + break + else: + frame = frame.f_back + return options + + +def get_linter_option(options, name, type, default): if name not in options: return default