Skip to content

Commit a3f2944

Browse files
juntyrkarroffel
authored andcommitted
Fixed {} in assert message, self in post, and unbound patterns
1 parent edc5ea5 commit a3f2944

File tree

5 files changed

+96
-10
lines changed

5 files changed

+96
-10
lines changed

.gitlab-ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,17 @@ test-stable:
1818
- cargo test --all
1919

2020

21-
2221
test-nightly:
2322
stage: test
2423
image: rustlang/rust:nightly
2524
script:
2625
- cargo test --all
2726
allow_failure: true
27+
28+
clippy-tests-stable:
29+
stage: test
30+
image: rust:latest
31+
before_script:
32+
- rustup component add clippy
33+
script:
34+
- cargo clippy --tests

src/implementation/codegen.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ pub(crate) fn generate(
188188
result.extend(
189189
quote::quote_spanned! { span=>
190190
if !(#exec_expr) {
191-
log::error!(#format_args);
191+
log::error!("{}", #format_args);
192192
}
193193
}
194194
.into_iter(),
@@ -198,7 +198,7 @@ pub(crate) fn generate(
198198
if let Some(assert_macro) = get_assert_macro(ctype, mode, span) {
199199
result.extend(
200200
quote::quote_spanned! { span=>
201-
#assert_macro!(#exec_expr, #format_args);
201+
#assert_macro!(#exec_expr, "{}", #format_args);
202202
}
203203
.into_iter(),
204204
);
@@ -460,7 +460,21 @@ fn create_body_closure(func: &syn::ItemFn) -> TokenStream {
460460
}
461461

462462
closure_args.push(receiver);
463-
arg_names.push(syn::Ident::new("self", Span::call_site()));
463+
464+
match &func.sig.inputs[0] {
465+
syn::FnArg::Receiver(receiver) => {
466+
arg_names
467+
.push(syn::Ident::new("self", receiver.self_token.span()));
468+
}
469+
syn::FnArg::Typed(pat) => {
470+
if let syn::Pat::Ident(ident) = &*pat.pat {
471+
arg_names.push(ident.ident.clone());
472+
} else {
473+
// Non-trivial receiver pattern => do not capture
474+
closure_args.pop();
475+
}
476+
}
477+
};
464478

465479
// Replace any references to `self` in the function body with references to `this`.
466480
syn::visit_mut::visit_block_mut(
@@ -482,8 +496,16 @@ fn create_body_closure(func: &syn::ItemFn) -> TokenStream {
482496
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
483497
if !ty_contains_impl_trait(ty) {
484498
if let syn::Pat::Ident(ident) = &**pat {
485-
arg_names.push(ident.ident.clone());
486-
closure_args.push(arg.clone());
499+
let ident_str = ident.ident.to_string();
500+
501+
// Any function argument identifier starting with '_' signals
502+
// that the binding will not be used.
503+
if !ident_str.starts_with('_')
504+
|| ident_str.starts_with("__")
505+
{
506+
arg_names.push(ident.ident.clone());
507+
closure_args.push(arg.clone());
508+
}
487509
}
488510
}
489511
}

tests/functions.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ fn test_impl_trait_return() {
117117
// qualified types works properly.
118118

119119
#[requires(x >= 10)]
120-
#[ensures(ret.clone() == ret)]
120+
#[ensures(Clone::clone(&ret) == ret)]
121+
#[allow(unused_variables)]
121122
fn impl_test(x: isize) -> impl Clone + PartialEq + std::fmt::Debug {
122123
"it worked"
123124
}
@@ -132,16 +133,37 @@ fn test_impl_trait_return() {
132133

133134
#[test]
134135
fn test_impl_trait_arg() {
135-
#[requires(x.clone() == x)]
136-
#[ensures(ret.clone() == ret)]
136+
#[requires(Clone::clone(&x) == x)]
137+
#[ensures(Clone::clone(&ret) == ret)]
137138
fn impl_test(x: impl Clone + PartialEq + std::fmt::Debug) -> &'static str {
138139
"it worked"
139140
}
140141

141142
let x = impl_test(200);
142-
let y = x.clone();
143+
let y = Clone::clone(&x);
143144
assert_eq!(
144145
format!("{:?} and {:?}", x, y),
145146
r#""it worked" and "it worked""#
146147
);
147148
}
149+
150+
#[test]
151+
#[deny(clippy::used_underscore_binding)]
152+
fn test_unbound_parameters_clippy() {
153+
#[requires(__y == 3)]
154+
#[ensures(ret)]
155+
fn param_test(_x: i32, __y: i32) -> bool {
156+
true
157+
}
158+
}
159+
160+
#[test]
161+
#[deny(non_fmt_panic)]
162+
fn test_braced_condition_expression_clippy() {
163+
#[requires(if __y == 3 {
164+
__y != 0
165+
} else {
166+
false
167+
})]
168+
fn param_test(_x: i32, __y: i32) {}
169+
}

tests/implication.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ fn test_requires_implication() {
5353
#[should_panic(expected = "Post")]
5454
fn test_failing_implication() {
5555
#[ensures(t -> ret)]
56+
#[allow(unused_variables)]
5657
fn only_true(t: bool) -> bool {
5758
false // oops
5859
}

tests/methods.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,37 @@ fn impl_invariant() {
101101
adder.prev_even();
102102
adder.prev_even();
103103
}
104+
105+
#[test]
106+
fn test_self_macro_hygiene() {
107+
struct S {
108+
value: i32,
109+
}
110+
111+
// Use a macro to generate the function impl
112+
// This requires strict hygiene of the `self` receiver
113+
macro_rules! __impl {
114+
(
115+
$(#[$metas:meta])*
116+
fn $function:ident(&mut $this:ident, $value:ident: $ty:ty)
117+
$body:block
118+
) => {
119+
$(#[$metas])*
120+
fn $function(&mut $this, $value: $ty)
121+
$body
122+
};
123+
}
124+
125+
impl S {
126+
__impl! {
127+
#[ensures(self.value == old(value))]
128+
fn set_value(&mut self, value: i32) {
129+
self.value = value;
130+
}
131+
}
132+
}
133+
134+
let mut s = S { value: 24 };
135+
s.set_value(42);
136+
assert_eq!(s.value, 42);
137+
}

0 commit comments

Comments
 (0)