aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/snippets/rust-clippy-driver-support.md6
-rw-r--r--mesonbuild/compilers/__init__.py3
-rw-r--r--mesonbuild/compilers/detect.py23
-rw-r--r--mesonbuild/compilers/rust.py17
-rw-r--r--test cases/rust/1 basic/clippy.toml1
-rw-r--r--test cases/rust/1 basic/prog.rs3
-rw-r--r--unittests/allplatformstests.py13
-rw-r--r--unittests/baseplatformtests.py5
8 files changed, 59 insertions, 12 deletions
diff --git a/docs/markdown/snippets/rust-clippy-driver-support.md b/docs/markdown/snippets/rust-clippy-driver-support.md
new file mode 100644
index 0000000..c486473
--- /dev/null
+++ b/docs/markdown/snippets/rust-clippy-driver-support.md
@@ -0,0 +1,6 @@
+## Support for clippy-driver as a rustc wrapper
+
+Clippy is a popular linting tool for Rust, and is invoked in place of rustc as a
+wrapper. Unfortunately it doesn't proxy rustc's output, so we need to have a
+small wrapper around it so that Meson can correctly detect the underlying rustc,
+but still display clippy
diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py
index 8c5275c..98b0b5f 100644
--- a/mesonbuild/compilers/__init__.py
+++ b/mesonbuild/compilers/__init__.py
@@ -112,6 +112,7 @@ __all__ = [
'PGICPPCompiler',
'PGIFortranCompiler',
'RustCompiler',
+ 'ClippyRustCompiler',
'CcrxCCompiler',
'CcrxCPPCompiler',
'Xc16CCompiler',
@@ -241,7 +242,7 @@ from .objcpp import (
ClangObjCPPCompiler,
GnuObjCPPCompiler,
)
-from .rust import RustCompiler
+from .rust import RustCompiler, ClippyRustCompiler
from .swift import SwiftCompiler
from .vala import ValaCompiler
from .mixins.visualstudio import VisualStudioLikeCompiler
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py
index 6426380..52ad7f3 100644
--- a/mesonbuild/compilers/detect.py
+++ b/mesonbuild/compilers/detect.py
@@ -124,7 +124,7 @@ from .objcpp import (
GnuObjCPPCompiler,
)
from .cython import CythonCompiler
-from .rust import RustCompiler
+from .rust import RustCompiler, ClippyRustCompiler
from .swift import SwiftCompiler
from .vala import ValaCompiler
from .mixins.visualstudio import VisualStudioLikeCompiler
@@ -952,6 +952,13 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
continue
version = search_version(out)
+ cls: T.Type[RustCompiler] = RustCompiler
+
+ # Clippy is a wrapper around rustc, but it doesn't have rustc in it's
+ # output. We can otherwise treat it as rustc.
+ if 'clippy' in out:
+ out = 'rustc'
+ cls = ClippyRustCompiler
if 'rustc' in out:
# On Linux and mac rustc will invoke gcc (clang for mac
@@ -976,7 +983,7 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
extra_args: T.Dict[str, T.Union[str, bool]] = {}
always_args: T.List[str] = []
if is_link_exe:
- compiler.extend(RustCompiler.use_linker_args(cc.linker.exelist[0]))
+ compiler.extend(cls.use_linker_args(cc.linker.exelist[0]))
extra_args['direct'] = True
extra_args['machine'] = cc.linker.machine
else:
@@ -984,7 +991,7 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
if 'ccache' in exelist[0]:
del exelist[0]
c = exelist.pop(0)
- compiler.extend(RustCompiler.use_linker_args(c))
+ compiler.extend(cls.use_linker_args(c))
# Also ensure that we pass any extra arguments to the linker
for l in exelist:
@@ -1002,12 +1009,12 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
**extra_args) # type: ignore
elif 'link' in override[0]:
linker = guess_win_linker(env,
- override, RustCompiler, for_machine, use_linker_prefix=False)
+ override, cls, for_machine, use_linker_prefix=False)
# rustc takes linker arguments without a prefix, and
# inserts the correct prefix itself.
assert isinstance(linker, VisualStudioLikeLinkerMixin)
linker.direct = True
- compiler.extend(RustCompiler.use_linker_args(linker.exelist[0]))
+ compiler.extend(cls.use_linker_args(linker.exelist[0]))
else:
# On linux and macos rust will invoke the c compiler for
# linking, on windows it will use lld-link or link.exe.
@@ -1019,10 +1026,10 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
# Of course, we're not going to use any of that, we just
# need it to get the proper arguments to pass to rustc
c = linker.exelist[1] if linker.exelist[0].endswith('ccache') else linker.exelist[0]
- compiler.extend(RustCompiler.use_linker_args(c))
+ compiler.extend(cls.use_linker_args(c))
- env.coredata.add_lang_args(RustCompiler.language, RustCompiler, for_machine, env)
- return RustCompiler(
+ env.coredata.add_lang_args(cls.language, cls, for_machine, env)
+ return cls(
compiler, version, for_machine, is_cross, info, exe_wrap,
linker=linker)
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index 2337ceb..9423b2d 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -196,3 +196,20 @@ class RustCompiler(Compiler):
# Rustc currently has no way to toggle this, it's controlled by whether
# pic is on by rustc
return []
+
+
+class ClippyRustCompiler(RustCompiler):
+
+ """Clippy is a linter that wraps Rustc.
+
+ This just provides us a different id
+ """
+
+ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
+ is_cross: bool, info: 'MachineInfo',
+ exe_wrapper: T.Optional['ExternalProgram'] = None,
+ full_version: T.Optional[str] = None,
+ linker: T.Optional['DynamicLinker'] = None):
+ super().__init__(exelist, version, for_machine, is_cross, info,
+ exe_wrapper, full_version, linker)
+ self.id = 'clippy-driver rustc'
diff --git a/test cases/rust/1 basic/clippy.toml b/test cases/rust/1 basic/clippy.toml
new file mode 100644
index 0000000..e9ac31b
--- /dev/null
+++ b/test cases/rust/1 basic/clippy.toml
@@ -0,0 +1 @@
+blacklisted-names = ["foo"]
diff --git a/test cases/rust/1 basic/prog.rs b/test cases/rust/1 basic/prog.rs
index b171a80..f1b3d30 100644
--- a/test cases/rust/1 basic/prog.rs
+++ b/test cases/rust/1 basic/prog.rs
@@ -1,3 +1,4 @@
fn main() {
- println!("rust compiler is working");
+ let foo = "rust compiler is working";
+ println!("{}", foo);
}
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 7afa989..93a2e49 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -4034,3 +4034,16 @@ class AllPlatformTests(BasePlatformTests):
for file, details in files.items():
with self.subTest(key='{}.{}'.format(data_type, file)):
self.assertEqual(res[data_type][file], details)
+
+ @skip_if_not_language('rust')
+ @unittest.skipIf(not shutil.which('clippy-driver'), 'Test requires clippy-driver')
+ def test_rust_clippy(self) -> None:
+ if self.backend is not Backend.ninja:
+ raise unittest.SkipTest('Rust is only supported with ninja currently')
+ # Wehn clippy is used, we should get an exception since a variable named
+ # "foo" is used, but is on our denylist
+ testdir = os.path.join(self.rust_test_dir, '1 basic')
+ self.init(testdir, extra_args=['--werror'], override_envvars={'RUSTC': 'clippy-driver'})
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ self.build()
+ self.assertIn('error: use of a blacklisted/placeholder name `foo`', cm.exception.stdout)
diff --git a/unittests/baseplatformtests.py b/unittests/baseplatformtests.py
index 3492785..9371395 100644
--- a/unittests/baseplatformtests.py
+++ b/unittests/baseplatformtests.py
@@ -69,6 +69,7 @@ class BasePlatformTests(TestCase):
self.uninstall_command = get_backend_commands(self.backend)
# Test directories
self.common_test_dir = os.path.join(src_root, 'test cases/common')
+ self.rust_test_dir = os.path.join(src_root, 'test cases/rust')
self.vala_test_dir = os.path.join(src_root, 'test cases/vala')
self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks')
self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
@@ -135,7 +136,7 @@ class BasePlatformTests(TestCase):
os.environ.update(self.orig_env)
super().tearDown()
- def _run(self, command, *, workdir=None, override_envvars=None):
+ def _run(self, command, *, workdir=None, override_envvars: T.Optional[T.Mapping[str, str]] = None):
'''
Run a command while printing the stdout and stderr to stdout,
and also return a copy of it
@@ -164,7 +165,7 @@ class BasePlatformTests(TestCase):
extra_args=None,
default_args=True,
inprocess=False,
- override_envvars=None,
+ override_envvars: T.Optional[T.Mapping[str, str]] = None,
workdir=None,
allow_fail: bool = False) -> str:
"""Call `meson setup`