diff options
| -rw-r--r-- | mesonbuild/backend/ninjabackend.py | 5 | ||||
| -rw-r--r-- | mesonbuild/environment.py | 26 | ||||
| -rw-r--r-- | mesonbuild/scripts/clangtidy.py | 50 |
3 files changed, 72 insertions, 9 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index d8995f031..6eb1f1d01 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -3666,10 +3666,11 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.generate_clangtool('format', 'check') def generate_clangtidy(self) -> None: - import shutil - if not shutil.which('clang-tidy'): + if not environment.detect_clangtidy(): return self.generate_clangtool('tidy') + if not environment.detect_clangapply(): + return self.generate_clangtool('tidy', 'fix') def generate_tags(self, tool: str, target_name: str) -> None: diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 90c9bb911..71a2f3afc 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -275,6 +275,32 @@ def detect_clangformat() -> T.List[str]: return [path] return [] +def detect_clangtidy() -> T.List[str]: + """ Look for clang-tidy binary on build platform + + Return: a single-element list of the found clang-tidy binary ready to be + passed to Popen() + """ + tools = get_llvm_tool_names('clang-tidy') + for tool in tools: + path = shutil.which(tool) + if path is not None: + return [path] + return [] + +def detect_clangapply() -> T.List[str]: + """ Look for clang-apply-replacements binary on build platform + + Return: a single-element list of the found clang-apply-replacements binary + ready to be passed to Popen() + """ + tools = get_llvm_tool_names('clang-apply-replacements') + for tool in tools: + path = shutil.which(tool) + if path is not None: + return [path] + return [] + def detect_windows_arch(compilers: CompilersDict) -> str: """ Detecting the 'native' architecture of Windows is not a trivial task. We diff --git a/mesonbuild/scripts/clangtidy.py b/mesonbuild/scripts/clangtidy.py index 1e0c4a5a3..a922f8514 100644 --- a/mesonbuild/scripts/clangtidy.py +++ b/mesonbuild/scripts/clangtidy.py @@ -6,15 +6,22 @@ from __future__ import annotations import argparse import subprocess from pathlib import Path +import tempfile +import os +import shutil +import sys from .run_tool import run_tool +from ..environment import detect_clangtidy, detect_clangapply import typing as T -def run_clang_tidy(fname: Path, builddir: Path) -> subprocess.CompletedProcess: - return subprocess.run(['clang-tidy', '-quiet', '-p', str(builddir), str(fname)]) - -def run_clang_tidy_fix(fname: Path, builddir: Path) -> subprocess.CompletedProcess: - return subprocess.run(['run-clang-tidy', '-fix', '-format', '-quiet', '-p', str(builddir), str(fname)]) +def run_clang_tidy(fname: Path, tidyexe: list, builddir: Path, fixesdir: T.Optional[Path]) -> subprocess.CompletedProcess: + args = [] + if fixesdir is not None: + handle, name = tempfile.mkstemp(prefix=fname.name + '.', suffix='.yaml', dir=fixesdir) + os.close(handle) + args.extend(['-export-fixes', name]) + return subprocess.run(tidyexe + args + ['-quiet', '-p', str(builddir), str(fname)]) def run(args: T.List[str]) -> int: parser = argparse.ArgumentParser() @@ -26,5 +33,34 @@ def run(args: T.List[str]) -> int: srcdir = Path(options.sourcedir) builddir = Path(options.builddir) - run_func = run_clang_tidy_fix if options.fix else run_clang_tidy - return run_tool('clang-tidy', srcdir, builddir, run_func, builddir) + tidyexe = detect_clangtidy() + if not tidyexe: + print(f'Could not execute clang-tidy "{" ".join(tidyexe)}"') + return 1 + + fixesdir: T.Optional[Path] = None + if options.fix: + applyexe = detect_clangapply() + if not applyexe: + print(f'Could not execute clang-apply-replacements "{" ".join(applyexe)}"') + return 1 + + fixesdir = builddir / 'meson-private' / 'clang-tidy-fix' + if fixesdir.is_dir(): + shutil.rmtree(fixesdir) + elif fixesdir.exists(): + fixesdir.unlink() + fixesdir.mkdir(parents=True) + + tidyret = run_tool('clang-tidy', srcdir, builddir, run_clang_tidy, tidyexe, builddir, fixesdir) + if fixesdir is not None: + print('Applying fix-its...') + applyret = subprocess.run(applyexe + ['-format', '-style=file', '-ignore-insert-conflict', fixesdir]).returncode + + if tidyret != 0: + print('Errors encountered while running clang-tidy', file=sys.stderr) + return tidyret + if fixesdir is not None and applyret != 0: + print('Errors encountered while running clang-apply-replacements', file=sys.stderr) + return applyret + return 0 |
