summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/ninjabackend.py5
-rw-r--r--mesonbuild/environment.py26
-rw-r--r--mesonbuild/scripts/clangtidy.py50
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