mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-07 22:04:10 -05:00
chore(lint): use dylint as lint driver for tfhe-lint
This commit is contained in:
committed by
Nicolas Sarlin
parent
7103a83ce5
commit
9a64c34989
@@ -1,11 +1,15 @@
|
||||
ignore:
|
||||
- .git
|
||||
- target
|
||||
- tfhe/build
|
||||
- venv
|
||||
- web-test-runner
|
||||
- tfhe/benchmarks_parameters
|
||||
- tfhe/web_wasm_parallel_tests/node_modules
|
||||
- tfhe/web_wasm_parallel_tests/dist
|
||||
- keys
|
||||
- coverage
|
||||
- utils/tfhe-lints/ui/main.stderr
|
||||
|
||||
rules:
|
||||
# checks if file ends in a newline character
|
||||
|
||||
@@ -16,8 +16,7 @@ members = [
|
||||
|
||||
exclude = [
|
||||
"tests/backward_compatibility_tests",
|
||||
"utils/cargo-tfhe-lints-inner",
|
||||
"utils/cargo-tfhe-lints"
|
||||
"utils/tfhe-lints",
|
||||
]
|
||||
[workspace.dependencies]
|
||||
aligned-vec = { version = "0.6", default-features = false }
|
||||
@@ -47,3 +46,8 @@ inherits = "dev"
|
||||
opt-level = 3
|
||||
lto = "off"
|
||||
debug-assertions = false
|
||||
|
||||
[workspace.metadata.dylint]
|
||||
libraries = [
|
||||
{ path = "utils/tfhe-lints" }
|
||||
]
|
||||
|
||||
31
Makefile
31
Makefile
@@ -151,10 +151,9 @@ install_tarpaulin: install_rs_build_toolchain
|
||||
cargo $(CARGO_RS_BUILD_TOOLCHAIN) install cargo-tarpaulin --locked || \
|
||||
( echo "Unable to install cargo tarpaulin, unknown error." && exit 1 )
|
||||
|
||||
.PHONY: install_tfhe_lints # Install custom tfhe-rs lints
|
||||
install_tfhe_lints:
|
||||
(cd utils/cargo-tfhe-lints-inner && cargo install --path .) && \
|
||||
cd utils/cargo-tfhe-lints && cargo install --path .
|
||||
.PHONY: install_cargo_dylint # Install custom tfhe-rs lints
|
||||
install_cargo_dylint:
|
||||
cargo install cargo-dylint dylint-link
|
||||
|
||||
.PHONY: install_typos_checker # Install typos checker
|
||||
install_typos_checker: install_rs_build_toolchain
|
||||
@@ -418,10 +417,15 @@ clippy_versionable: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
|
||||
-p tfhe-versionable -- --no-deps -D warnings
|
||||
|
||||
.PHONY: clippy_tfhe_lints # Run clippy lints on tfhe-lints
|
||||
clippy_tfhe_lints: install_cargo_dylint # the toolchain is selected with toolchain.toml
|
||||
cd utils/tfhe-lints && \
|
||||
cargo clippy --all-targets -- --no-deps -D warnings
|
||||
|
||||
.PHONY: clippy_all # Run all clippy targets
|
||||
clippy_all: clippy_rustdoc clippy clippy_boolean clippy_shortint clippy_integer clippy_all_targets \
|
||||
clippy_c_api clippy_js_wasm_api clippy_tasks clippy_core clippy_tfhe_csprng clippy_zk_pok clippy_trivium \
|
||||
clippy_versionable
|
||||
clippy_versionable clippy_tfhe_lints
|
||||
|
||||
.PHONY: clippy_fast # Run main clippy targets
|
||||
clippy_fast: clippy_rustdoc clippy clippy_all_targets clippy_c_api clippy_js_wasm_api clippy_tasks \
|
||||
@@ -441,9 +445,9 @@ check_rust_bindings_did_not_change:
|
||||
|
||||
|
||||
.PHONY: tfhe_lints # Run custom tfhe-rs lints
|
||||
tfhe_lints: install_tfhe_lints
|
||||
cd tfhe && RUSTFLAGS="$(RUSTFLAGS)" cargo tfhe-lints \
|
||||
--features=boolean,shortint,integer,zk-pok -- -D warnings
|
||||
tfhe_lints: install_cargo_dylint
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo dylint --all -p tfhe --no-deps -- \
|
||||
--features=boolean,shortint,integer,strings,zk-pok
|
||||
|
||||
.PHONY: build_core # Build core_crypto without experimental features
|
||||
build_core: install_rs_build_toolchain install_rs_check_toolchain
|
||||
@@ -889,6 +893,11 @@ test_versionable: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
--all-targets -p tfhe-versionable
|
||||
|
||||
.PHONY: test_tfhe_lints # Run test on tfhe-lints
|
||||
test_tfhe_lints: install_cargo_dylint
|
||||
cd utils/tfhe-lints && \
|
||||
cargo test
|
||||
|
||||
# The backward compat data repo holds historical binary data but also rust code to generate and load them.
|
||||
# Here we use the "patch" functionality of Cargo to make sure the repo used for the data is the same as the one used for the code.
|
||||
.PHONY: test_backward_compatibility_ci
|
||||
@@ -1305,9 +1314,7 @@ sha256_bool: install_rs_check_toolchain
|
||||
|
||||
.PHONY: pcc # pcc stands for pre commit checks (except GPU)
|
||||
pcc: no_tfhe_typo no_dbg_log check_fmt check_typos lint_doc check_md_docs_are_tested check_intra_md_links \
|
||||
clippy_all check_compile_tests
|
||||
# TFHE lints deactivated as it's incompatible with 1.83 - temporary
|
||||
# tfhe_lints
|
||||
clippy_all check_compile_tests test_tfhe_lints tfhe_lints
|
||||
|
||||
.PHONY: pcc_gpu # pcc stands for pre commit checks for GPU compilation
|
||||
pcc_gpu: clippy_gpu clippy_cuda_backend check_compile_tests_benches_gpu check_rust_bindings_did_not_change
|
||||
@@ -1317,7 +1324,7 @@ fpcc: no_tfhe_typo no_dbg_log check_fmt check_typos lint_doc check_md_docs_are_t
|
||||
check_compile_tests
|
||||
|
||||
.PHONY: conformance # Automatically fix problems that can be fixed
|
||||
conformance: fmt fmt_js
|
||||
conformance: fix_newline fmt fmt_js
|
||||
|
||||
#=============================== FFT Section ==================================
|
||||
.PHONY: doc_fft # Build rust doc for tfhe-fft
|
||||
|
||||
@@ -10,7 +10,7 @@ const DIR_TO_IGNORE: [&str; 3] = [
|
||||
"tests/tfhe-backward-compat-data",
|
||||
];
|
||||
|
||||
const FILES_TO_IGNORE: [&str; 5] = [
|
||||
const FILES_TO_IGNORE: [&str; 6] = [
|
||||
// This contains fragments of code that are unrelated to TFHE-rs
|
||||
"tfhe/docs/tutorials/sha256_bool.md",
|
||||
// TODO: This contains code that could be executed as a trivium docstring
|
||||
@@ -21,6 +21,7 @@ const FILES_TO_IGNORE: [&str; 5] = [
|
||||
"tfhe-fft/README.md",
|
||||
// TODO: find a way to test the tfhe-ntt readme
|
||||
"tfhe-ntt/README.md",
|
||||
"utils/tfhe-lints/README.md",
|
||||
];
|
||||
|
||||
pub fn check_tfhe_docs_are_tested() -> Result<(), Error> {
|
||||
|
||||
@@ -311,7 +311,7 @@ crate-type = ["lib", "staticlib", "cdylib"]
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = [
|
||||
'cfg(tarpaulin)',
|
||||
'cfg(tfhe_lints)',
|
||||
'cfg(dylint_lib, values(any()))',
|
||||
# This is a bug/unwanted behavior from wasm_bindgen macro, for now warn instead of erroring
|
||||
'cfg(wasm_bindgen_unstable_test_coverage)',
|
||||
] }
|
||||
|
||||
@@ -19,7 +19,6 @@ pub enum DynamicDistributionVersions<T: UnsignedInteger> {
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub enum CompressionSeedVersioned<'vers> {
|
||||
V0(&'vers CompressionSeed),
|
||||
}
|
||||
@@ -31,7 +30,6 @@ impl<'vers> From<&'vers CompressionSeed> for CompressionSeedVersioned<'vers> {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub enum CompressionSeedVersionedOwned {
|
||||
V0(CompressionSeed),
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ use crate::core_crypto::prelude::{
|
||||
};
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub enum FourierPolynomialListVersioned<'vers> {
|
||||
V0(FourierPolynomialList<&'vers [c64]>),
|
||||
}
|
||||
@@ -31,7 +30,6 @@ impl<'vers, C: Container<Element = c64>> From<&'vers FourierPolynomialList<C>>
|
||||
|
||||
// Here we do not derive "VersionsDispatch" so that we can implement a non recursive Versionize
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub enum FourierPolynomialListVersionedOwned {
|
||||
V0(FourierPolynomialList<ABox<[c64]>>),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
// Backward compatibility types should not be themselves versioned
|
||||
#![cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
|
||||
pub mod commons;
|
||||
pub mod entities;
|
||||
|
||||
@@ -623,12 +623,12 @@ impl<C: Container<Element = c64>> serde::Serialize for FourierPolynomialList<C>
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
use crate::core_crypto::commons::traits::Split;
|
||||
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub struct SingleFourierPolynomial<'a> {
|
||||
fft: FftView<'a>,
|
||||
buf: &'a [c64],
|
||||
}
|
||||
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
impl serde::Serialize for SingleFourierPolynomial<'_> {
|
||||
fn serialize<S: serde::Serializer>(
|
||||
&self,
|
||||
|
||||
@@ -9,7 +9,6 @@ use std::convert::Infallible;
|
||||
|
||||
// Manual impl
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub(crate) enum InnerBooleanVersionedOwned {
|
||||
V0(InnerBooleanVersionOwned),
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@ use self::unsigned::RadixCiphertext as UnsignedRadixCiphertext;
|
||||
|
||||
// Manual impl
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub(crate) enum SignedRadixCiphertextVersionedOwned {
|
||||
V0(SignedRadixCiphertextVersionOwned),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
pub(crate) enum UnsignedRadixCiphertextVersionedOwned {
|
||||
V0(UnsignedRadixCiphertextVersionOwned),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
// Backward compatibility types should not be themselves versioned
|
||||
#![cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
|
||||
pub mod booleans;
|
||||
pub mod compact_list;
|
||||
|
||||
@@ -52,7 +52,7 @@ impl<'de> serde::Deserialize<'de> for InnerBoolean {
|
||||
|
||||
// Only CPU data are serialized so we only versionize the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct InnerBooleanVersionOwned(
|
||||
<crate::integer::BooleanBlock as VersionizeOwned>::VersionedOwned,
|
||||
);
|
||||
|
||||
@@ -67,7 +67,7 @@ impl<'de> serde::Deserialize<'de> for RadixCiphertext {
|
||||
|
||||
// Only CPU data are serialized so we only versionize the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct RadixCiphertextVersionOwned(
|
||||
<crate::integer::SignedRadixCiphertext as VersionizeOwned>::VersionedOwned,
|
||||
);
|
||||
|
||||
@@ -63,7 +63,7 @@ impl<'de> serde::Deserialize<'de> for RadixCiphertext {
|
||||
|
||||
// Only CPU data are serialized so we only version the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct RadixCiphertextVersionOwned(
|
||||
<crate::integer::RadixCiphertext as VersionizeOwned>::VersionedOwned,
|
||||
);
|
||||
|
||||
@@ -157,7 +157,7 @@ impl AsRef<crate::integer::ServerKey> for ServerKey {
|
||||
// in multi-threading scenarios.
|
||||
#[derive(serde::Serialize)]
|
||||
// We directly versionize the `ServerKey` without having to use this intermediate type.
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
struct SerializableServerKey<'a> {
|
||||
pub(crate) integer_key: &'a IntegerServerKey,
|
||||
pub(crate) tag: &'a Tag,
|
||||
|
||||
@@ -77,11 +77,11 @@ impl<'de> serde::Deserialize<'de> for AsciiDevice {
|
||||
|
||||
// Only CPU data are serialized so we only versionize the CPU type.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) struct AsciiDeviceVersionOwned(<FheString as VersionizeOwned>::VersionedOwned);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub(crate) enum AsciiDeviceVersionedOwned {
|
||||
V0(AsciiDeviceVersionOwned),
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
//! Serialization utilities with some safety checks
|
||||
|
||||
// Types in this file should never be versioned because they are a wrapper around the versioning
|
||||
// process
|
||||
#![cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Display;
|
||||
|
||||
@@ -29,8 +33,6 @@ const CRATE_VERSION: &str = concat!(
|
||||
|
||||
/// Tells if this serialized object is versioned or not
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
// This type should not be versioned because it is part of a wrapper of versioned messages.
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
enum SerializationVersioningMode {
|
||||
/// Serialize with type versioning for backward compatibility
|
||||
Versioned {
|
||||
@@ -70,8 +72,6 @@ impl SerializationVersioningMode {
|
||||
/// Header with global metadata about the serialized object. This help checking that we are not
|
||||
/// deserializing data that we can't handle.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
// This type should not be versioned because it is part of a wrapper of versioned messages.
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
struct SerializationHeader {
|
||||
header_version: Cow<'static, str>,
|
||||
versioning_mode: SerializationVersioningMode,
|
||||
|
||||
@@ -17,7 +17,7 @@ mod test;
|
||||
|
||||
// Struct for WoPBS based on the private functional packing keyswitch.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]
|
||||
#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
|
||||
pub struct WopbsKey {
|
||||
//Key for the private functional keyswitch
|
||||
pub wopbs_server_key: ServerKey,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "cargo-tfhe-lints-inner"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rustc-tools = "0.80"
|
||||
|
||||
[package.metadata.rust-analyzer]
|
||||
rustc_private=true
|
||||
@@ -1,16 +0,0 @@
|
||||
# TFHE-lints-inner
|
||||
|
||||
Implementation of the lints in the custom [tfhe-lints](../cargo-tfhe-lints/README.md) tool.
|
||||
|
||||
## Installation
|
||||
```
|
||||
cargo install --path .
|
||||
```
|
||||
|
||||
## Usage
|
||||
This can be run directly by specifying the toolchain:
|
||||
```
|
||||
cargo +nightly-2024-05-02 tfhe-lints-inner
|
||||
```
|
||||
|
||||
For a more ergonomic usage, see [tfhe-lints](../cargo-tfhe-lints/README.md)
|
||||
@@ -1,4 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2024-07-25"
|
||||
components = ["rustc-dev", "rust-src", "llvm-tools-preview"]
|
||||
profile = "minimal"
|
||||
@@ -1,59 +0,0 @@
|
||||
#![feature(rustc_private)]
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::must_use_candidate)]
|
||||
|
||||
mod serialize_without_versionize;
|
||||
pub mod utils;
|
||||
|
||||
// We need to import them like this otherwise it doesn't work.
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_lint;
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_tools::with_lints;
|
||||
use serialize_without_versionize::SerializeWithoutVersionize;
|
||||
|
||||
fn main() {
|
||||
let tool_args = std::env::args().skip(2).collect::<Vec<_>>();
|
||||
|
||||
let (cargo_args, rustc_args) = if let Some(idx) = tool_args.iter().position(|arg| arg == "--") {
|
||||
tool_args.split_at(idx)
|
||||
} else {
|
||||
(tool_args.as_slice(), &[] as &[String])
|
||||
};
|
||||
|
||||
// The linter calls rustc without cargo, so these variables won't be set. Since we use them in
|
||||
// our code, we need to set them to any value to avoid a compilation error.
|
||||
std::env::set_var("CARGO_PKG_VERSION_MAJOR", "X");
|
||||
std::env::set_var("CARGO_PKG_VERSION_MINOR", "Y");
|
||||
|
||||
rustc_tools::cargo_integration(&cargo_args, |args| {
|
||||
let mut args = args.to_vec();
|
||||
args.extend(rustc_args.iter().skip(1).cloned());
|
||||
args.extend(
|
||||
[
|
||||
"--emit=metadata",
|
||||
// These params allows to use the syntax
|
||||
// `#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]`
|
||||
"-Zcrate-attr=feature(register_tool)",
|
||||
"-Zcrate-attr=register_tool(tfhe_lints)",
|
||||
"--cfg=tfhe_lints",
|
||||
]
|
||||
.iter()
|
||||
.map(ToString::to_string),
|
||||
);
|
||||
let serialize_without_versionize = SerializeWithoutVersionize::new();
|
||||
|
||||
with_lints(&args, vec![], move |store: &mut LintStore| {
|
||||
let lint = serialize_without_versionize.clone();
|
||||
store.register_late_pass(move |_| Box::new(lint.clone()));
|
||||
})
|
||||
.expect("with_lints failed");
|
||||
})
|
||||
.expect("cargo_integration failed");
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "cargo-tfhe-lints"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,25 +0,0 @@
|
||||
# TFHE-lints
|
||||
|
||||
A collection of rust lints specific to the **TFHE-rs** project. This tool is built using [rustc-tools](https://github.com/GuillaumeGomez/rustc-tools).
|
||||
|
||||
## List of lints
|
||||
- `serilaize_without_versionize`: warns if `Serialize` is implemented without `Versionize`
|
||||
|
||||
## Installation
|
||||
|
||||
### Install the inner tool
|
||||
```
|
||||
cargo install --path ../cargo-tfhe-lints-inner
|
||||
```
|
||||
|
||||
### Install this wrapper
|
||||
```
|
||||
cargo install --path .
|
||||
```
|
||||
|
||||
## Usage
|
||||
Use it as any other cargo tool:
|
||||
```
|
||||
cargo tfhe-lints
|
||||
```
|
||||
You can specify features like you would do with clippy.
|
||||
@@ -1,50 +0,0 @@
|
||||
use std::{
|
||||
io::{Error, ErrorKind},
|
||||
process::{exit, Command},
|
||||
};
|
||||
|
||||
fn get_supported_rustc_version() -> &'static str {
|
||||
const TOOLCHAIN_FILE: &str = include_str!("../../cargo-tfhe-lints-inner/rust-toolchain.toml");
|
||||
|
||||
TOOLCHAIN_FILE
|
||||
.lines()
|
||||
.find(|line| line.starts_with("channel"))
|
||||
.and_then(|line| {
|
||||
line.rsplit('=')
|
||||
.next()
|
||||
.unwrap()
|
||||
.trim()
|
||||
.strip_prefix('"')
|
||||
.unwrap()
|
||||
.strip_suffix('"')
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cargo_args = std::env::args().skip(2).collect::<Vec<_>>();
|
||||
let toolchain = format!("+{}", get_supported_rustc_version());
|
||||
|
||||
if let Err(err) = Command::new("cargo")
|
||||
.arg(toolchain.as_str())
|
||||
.arg("tfhe-lints-inner")
|
||||
.args(&cargo_args)
|
||||
.status()
|
||||
.and_then(|res| {
|
||||
if !res.success() {
|
||||
Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Inner process failed with {res}"),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
{
|
||||
eprintln!(
|
||||
"Command `cargo {toolchain} tfhe-lints-inner {}` failed: {err:?}",
|
||||
cargo_args.join(" "),
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
5
utils/tfhe-lints/.cargo/config.toml
Normal file
5
utils/tfhe-lints/.cargo/config.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[build]
|
||||
target-dir = "../../target/tfhe-lints"
|
||||
|
||||
[target.'cfg(all())']
|
||||
linker = "dylint-link"
|
||||
25
utils/tfhe-lints/Cargo.toml
Normal file
25
utils/tfhe-lints/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "tfhe-lints"
|
||||
version = "0.1.0"
|
||||
description = "Project specific lints for TFHE-rs"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "ff4a26d442bead94a4c96fb1de967374bc4fbd8e" }
|
||||
dylint_linting = "3.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
dylint_testing = "3.2.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tfhe-versionable = "0.4.0"
|
||||
|
||||
[package.metadata.rust-analyzer]
|
||||
rustc_private = true
|
||||
|
||||
[[example]]
|
||||
name = "ui"
|
||||
path = "ui/main.rs"
|
||||
29
utils/tfhe-lints/README.md
Normal file
29
utils/tfhe-lints/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Project specific lints for TFHE-rs
|
||||
This tool is based on [dylint](https://github.com/trailofbits/dylint).
|
||||
|
||||
## Usage
|
||||
From TFHE-rs root folder:
|
||||
```
|
||||
make tfhe_lints
|
||||
```
|
||||
|
||||
## `serialize_without_versionize`
|
||||
|
||||
### What it does
|
||||
For every type that implements `Serialize`, checks that it also implement `Versionize`
|
||||
|
||||
### Why is this bad?
|
||||
If a type is serializable but does not implement Versionize, it is likely that the
|
||||
implementation has been forgotten.
|
||||
|
||||
### Example
|
||||
```rust
|
||||
#[derive(Serialize)]
|
||||
pub struct MyStruct {}
|
||||
```
|
||||
Use instead:
|
||||
```rust
|
||||
#[derive(Serialize, Versionize)]
|
||||
#[versionize(MyStructVersions)]
|
||||
pub struct MyStruct {}
|
||||
```
|
||||
3
utils/tfhe-lints/rust-toolchain
Normal file
3
utils/tfhe-lints/rust-toolchain
Normal file
@@ -0,0 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2024-11-28"
|
||||
components = ["llvm-tools-preview", "rustc-dev"]
|
||||
12
utils/tfhe-lints/src/lib.rs
Normal file
12
utils/tfhe-lints/src/lib.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![feature(rustc_private)]
|
||||
#![feature(let_chains)]
|
||||
#![warn(unused_extern_crates)]
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_lint;
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_span;
|
||||
|
||||
mod serialize_without_versionize;
|
||||
mod utils;
|
||||
@@ -3,17 +3,10 @@ use std::sync::{Arc, OnceLock};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Impl, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::utils::{get_def_id_from_ty, is_allowed_lint, symbols_list_from_str};
|
||||
|
||||
declare_tool_lint! {
|
||||
pub tfhe_lints::SERIALIZE_WITHOUT_VERSIONIZE,
|
||||
Warn,
|
||||
"warns if `Serialize` is implemented without `Versionize`"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SerializeWithoutVersionizeInner {
|
||||
pub versionize_trait: OnceLock<Option<DefId>>,
|
||||
@@ -42,14 +35,31 @@ impl SerializeWithoutVersionizeInner {
|
||||
#[derive(Default, Clone)]
|
||||
pub struct SerializeWithoutVersionize(pub Arc<SerializeWithoutVersionizeInner>);
|
||||
|
||||
impl SerializeWithoutVersionize {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
dylint_linting::impl_late_lint! {
|
||||
/// ### What it does
|
||||
/// For every type that implements `Serialize`, checks that it also implement `Versionize`
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// If a type is serializable but does not implement Versionize, it is likely that the
|
||||
/// implementation has been forgotten.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// #[derive(Serialize)]
|
||||
/// pub struct MyStruct {}
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// #[derive(Serialize, Versionize)]
|
||||
/// #[versionize(MyStructVersions)]
|
||||
/// pub struct MyStruct {}
|
||||
/// ```
|
||||
pub SERIALIZE_WITHOUT_VERSIONIZE,
|
||||
Warn,
|
||||
"Detects types that implement Serialize without implementing Versionize",
|
||||
SerializeWithoutVersionize::default()
|
||||
}
|
||||
|
||||
impl_lint_pass!(SerializeWithoutVersionize => [SERIALIZE_WITHOUT_VERSIONIZE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for SerializeWithoutVersionize {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
// If the currently checked item is a trait impl
|
||||
@@ -74,14 +84,12 @@ impl<'tcx> LateLintPass<'tcx> for SerializeWithoutVersionize {
|
||||
}
|
||||
|
||||
// Check if the implemented trait is `Serialize`
|
||||
if let Some(versionize_trait) = self.0.versionize_trait(cx) {
|
||||
if let Some(def_id) = trait_ref.trait_def_id() {
|
||||
if cx.match_def_path(
|
||||
def_id,
|
||||
symbols_list_from_str(&SERIALIZE_TRAIT).as_slice(),
|
||||
) {
|
||||
// Try to find an implementation of versionize for this type
|
||||
let mut found_impl = false;
|
||||
if let Some(def_id) = trait_ref.trait_def_id() {
|
||||
if cx.match_def_path(def_id, symbols_list_from_str(&SERIALIZE_TRAIT).as_slice())
|
||||
{
|
||||
// Try to find an implementation of versionize for this type
|
||||
let mut found_impl = false;
|
||||
if let Some(versionize_trait) = self.0.versionize_trait(cx) {
|
||||
cx.tcx
|
||||
.for_each_relevant_impl(versionize_trait, ty, |impl_id| {
|
||||
if !found_impl {
|
||||
@@ -95,20 +103,20 @@ impl<'tcx> LateLintPass<'tcx> for SerializeWithoutVersionize {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if !found_impl {
|
||||
// Emit a warning
|
||||
cx.span_lint(
|
||||
SERIALIZE_WITHOUT_VERSIONIZE,
|
||||
cx.tcx.def_span(type_def_id),
|
||||
|diag| {
|
||||
diag.primary_message("Type {ty} implements `Serialize` but does not implement `Versionize`");
|
||||
diag.note("Add `#[derive(Versionize)] for this type or silence this warning using \
|
||||
`#[cfg_attr(tfhe_lints, allow(tfhe_lints::serialize_without_versionize))]``");
|
||||
diag.span_note(item.span, "`Serialize` derived here");
|
||||
},
|
||||
);
|
||||
}
|
||||
if !found_impl {
|
||||
// Emit a warning
|
||||
cx.span_lint(
|
||||
SERIALIZE_WITHOUT_VERSIONIZE,
|
||||
cx.tcx.def_span(type_def_id),
|
||||
|diag| {
|
||||
diag.primary_message(format!("Type {ty} implements `Serialize` but does not implement `Versionize`"));
|
||||
diag.note("Add `#[derive(Versionize)]` for this type or silence this warning using \
|
||||
`#[cfg_attr(dylint_lib = \"tfhe_lints\", allow(serialize_without_versionize))]`");
|
||||
diag.span_note(item.span, "`Serialize` derived here");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,3 +124,8 @@ impl<'tcx> LateLintPass<'tcx> for SerializeWithoutVersionize {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ui() {
|
||||
dylint_testing::ui_test_example(env!("CARGO_PKG_NAME"), "ui");
|
||||
}
|
||||
@@ -4,8 +4,6 @@ use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{Ty, TyKind};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
const TOOL_NAME: &str = "tfhe_lints";
|
||||
|
||||
/// Converts an array of str into a Vec of [`Symbol`]
|
||||
pub fn symbols_list_from_str(list: &[&str]) -> Vec<Symbol> {
|
||||
list.iter().map(|s| Symbol::intern(s)).collect()
|
||||
@@ -21,13 +19,8 @@ pub fn is_allowed_lint(cx: &LateContext<'_>, target: DefId, lint_name: &str) ->
|
||||
let mut trees = tokens.trees();
|
||||
|
||||
if let Some(TokenTree::Token(tool_token, _)) = trees.next() {
|
||||
if tool_token.is_ident_named(Symbol::intern(TOOL_NAME)) {
|
||||
trees.next();
|
||||
if let Some(TokenTree::Token(tool_token, _)) = trees.next() {
|
||||
if tool_token.is_ident_named(Symbol::intern(lint_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if tool_token.is_ident_named(Symbol::intern(lint_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
utils/tfhe-lints/ui/main.rs
Normal file
11
utils/tfhe-lints/ui/main.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MyStruct {
|
||||
value: u64,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let st = MyStruct { value: 42 };
|
||||
println!("{}", st.value);
|
||||
}
|
||||
17
utils/tfhe-lints/ui/main.stderr
Normal file
17
utils/tfhe-lints/ui/main.stderr
Normal file
@@ -0,0 +1,17 @@
|
||||
warning: Type MyStruct implements `Serialize` but does not implement `Versionize`
|
||||
--> $DIR/main.rs:4:1
|
||||
|
|
||||
LL | struct MyStruct {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: Add `#[derive(Versionize)]` for this type or silence this warning using `#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]`
|
||||
note: `Serialize` derived here
|
||||
--> $DIR/main.rs:3:10
|
||||
|
|
||||
LL | #[derive(Serialize)]
|
||||
| ^^^^^^^^^
|
||||
= note: `#[warn(serialize_without_versionize)]` on by default
|
||||
= note: this warning originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
Reference in New Issue
Block a user