# SPDX-License-Identifier: Apache-2.0 # Copyright 2024 The Meson development team from __future__ import annotations from collections import defaultdict import os import tempfile import typing as T from .run_tool import run_tool_on_targets, run_with_buffered_output from .. import build, mlog from ..mesonlib import MachineChoice, PerMachine if T.TYPE_CHECKING: from ..compilers.rust import RustCompiler class ClippyDriver: def __init__(self, build: build.Build, tempdir: str): self.tools: PerMachine[T.List[str]] = PerMachine([], []) self.warned: T.DefaultDict[str, bool] = defaultdict(lambda: False) self.tempdir = tempdir for machine in MachineChoice: compilers = build.environment.coredata.compilers[machine] if 'rust' in compilers: compiler = T.cast('RustCompiler', compilers['rust']) self.tools[machine] = compiler.get_rust_tool('clippy-driver', build.environment) def warn_missing_clippy(self, machine: str) -> None: if self.warned[machine]: return mlog.warning(f'clippy-driver not found for {machine} machine') self.warned[machine] = True def __call__(self, target: T.Dict[str, T.Any]) -> T.Iterable[T.Coroutine[None, None, int]]: for src_block in target['target_sources']: if 'compiler' in src_block and src_block['language'] == 'rust': clippy = getattr(self.tools, src_block['machine']) if not clippy: self.warn_missing_clippy(src_block['machine']) continue cmdlist = list(clippy) prev = None lints_cap = None for arg in src_block['parameters']: if prev == '--cap-lints': cmdlist.append(prev) lints_cap = arg prev = None elif prev: prev = None continue if arg in {'--emit', '--out-dir', '--cap-lints'}: prev = arg else: cmdlist.append(arg) # no use in running clippy if it wouldn't print anything anyway if lints_cap == 'allow': break cmdlist.extend(src_block['sources']) # the default for --emit is to go all the way to linking, # and --emit dep-info= is not enough for clippy to do # enough analysis, so use --emit metadata. cmdlist.append('--emit') cmdlist.append('metadata') cmdlist.append('--out-dir') cmdlist.append(self.tempdir) yield run_with_buffered_output(cmdlist) def run(args: T.List[str]) -> int: os.chdir(args[0]) build_data = build.load(os.getcwd()) with tempfile.TemporaryDirectory() as d: return run_tool_on_targets(ClippyDriver(build_data, d))