9276: internal: refactor diagnostics more r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-06-14 19:37:28 +00:00 committed by GitHub
commit ce8fdf3ab0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 359 additions and 341 deletions

View File

@ -23,7 +23,7 @@ mod tests {
check_diagnostics(
r#"
fn foo() { break; }
//^^^^^ break outside of loop
//^^^^^ error: break outside of loop
"#,
);
}

View File

@ -7,7 +7,7 @@ use text_edit::TextEdit;
use crate::{fix, Diagnostic, Severity};
pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) {
pub(crate) fn field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) {
match_ast! {
match node {
ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it),

View File

@ -49,26 +49,26 @@ fn f() {
// The three g̶e̶n̶d̶e̶r̶s̶ statements:
#[cfg(a)] fn f() {} // Item statement
//^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
#[cfg(a)] {} // Expression statement
//^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
#[cfg(a)] let x = 0; // let statement
//^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
abc(#[cfg(a)] 0);
//^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
let x = Struct {
#[cfg(a)] f: 0,
//^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
};
match () {
() => (),
#[cfg(a)] () => (),
//^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
}
#[cfg(a)] 0 // Trailing expression of block
//^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
//^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
}
"#,
);
@ -81,16 +81,16 @@ fn f() {
check(
r#"
#[cfg(no)] pub fn f() {}
//^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
//^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
#[cfg(no)] #[cfg(no2)] mod m;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled
#[cfg(all(not(a), b))] enum E {}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled
#[cfg(feature = "std")] use std;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled
"#,
);
}
@ -102,14 +102,14 @@ fn f() {
check(
r#"
#[cfg_attr(not(never), cfg(no))] fn f() {}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
#[cfg_attr(not(never), cfg(not(no)))] fn f() {}
#[cfg_attr(never, cfg(no))] fn g() {}
#[cfg_attr(not(never), inline, cfg(no))] fn h() {}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
"#,
);
}

View File

@ -149,7 +149,7 @@ impl TestStruct {
check_diagnostics(
r#"
fn FOO() {}
// ^^^ Function `FOO` should have snake_case name, e.g. `foo`
// ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo`
"#,
);
check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#);
@ -160,7 +160,7 @@ fn FOO() {}
check_diagnostics(
r#"
fn NonSnakeCaseName() {}
// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
// ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
"#,
);
}
@ -170,10 +170,10 @@ fn NonSnakeCaseName() {}
check_diagnostics(
r#"
fn foo(SomeParam: u8) {}
// ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
// ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param`
fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
// ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
// ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
"#,
);
}
@ -184,9 +184,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
r#"
fn foo() {
let SOME_VALUE = 10;
// ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
// ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
let AnotherValue = 20;
// ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
// ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value`
}
"#,
);
@ -197,10 +197,10 @@ fn foo() {
check_diagnostics(
r#"
struct non_camel_case_name {}
// ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
// ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
struct SCREAMING_CASE {}
// ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
// ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
"#,
);
}
@ -219,7 +219,7 @@ struct AABB {}
check_diagnostics(
r#"
struct SomeStruct { SomeField: u8 }
// ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
// ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field`
"#,
);
}
@ -229,10 +229,10 @@ struct SomeStruct { SomeField: u8 }
check_diagnostics(
r#"
enum some_enum { Val(u8) }
// ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
// ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
enum SOME_ENUM {}
// ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
// ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
"#,
);
}
@ -251,7 +251,7 @@ enum AABB {}
check_diagnostics(
r#"
enum SomeEnum { SOME_VARIANT(u8) }
// ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
// ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
"#,
);
}
@ -261,7 +261,7 @@ enum SomeEnum { SOME_VARIANT(u8) }
check_diagnostics(
r#"
const some_weird_const: u8 = 10;
// ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
// ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
"#,
);
}
@ -271,7 +271,7 @@ const some_weird_const: u8 = 10;
check_diagnostics(
r#"
static some_weird_const: u8 = 10;
// ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
// ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
"#,
);
}
@ -281,13 +281,13 @@ static some_weird_const: u8 = 10;
check_diagnostics(
r#"
struct someStruct;
// ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
// ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
impl someStruct {
fn SomeFunc(&self) {
// ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
// ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func`
let WHY_VAR_IS_CAPS = 10;
// ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
// ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
}
}
"#,
@ -319,7 +319,7 @@ enum Option { Some, None }
fn main() {
match Option::None {
SOME_VAR @ None => (),
// ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
// ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
Some => (),
}
}
@ -421,11 +421,11 @@ extern {
check_diagnostics(
r#"
trait BAD_TRAIT {
// ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
// ^^^^^^^^^ 💡 weak: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
fn BAD_FUNCTION();
// ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
// ^^^^^^^^^^^^ 💡 weak: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
fn BadFunction();
// ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
// ^^^^^^^^^^^^ 💡 weak: Function `BadFunction` should have snake_case name, e.g. `bad_function`
}
"#,
);

View File

@ -27,7 +27,7 @@ mod tests {
macro_rules! include { () => {} }
include!("doesntexist");
//^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist`
//^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist`
"#,
);
}
@ -66,7 +66,7 @@ macro_rules! env { () => {} }
macro_rules! concat { () => {} }
include!(concat!(env!("OUT_DIR"), "/out.rs"));
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
"#,
);
}
@ -108,23 +108,23 @@ fn main() {
// Test a handful of built-in (eager) macros:
include!(invalid);
//^^^^^^^^^^^^^^^^^ could not convert tokens
//^^^^^^^^^^^^^^^^^ error: could not convert tokens
include!("does not exist");
//^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist`
//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
env!(invalid);
//^^^^^^^^^^^^^ could not convert tokens
//^^^^^^^^^^^^^ error: could not convert tokens
env!("OUT_DIR");
//^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
//^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
compile_error!("compile_error works");
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works
// Lazy:
format_args!();
//^^^^^^^^^^^^^^ no rule matches input tokens
//^^^^^^^^^^^^^^ error: no rule matches input tokens
}
"#,
);
@ -141,7 +141,7 @@ fn f() {
m!();
m!(hi);
//^^^^^^ leftover tokens
//^^^^^^ error: leftover tokens
}
"#,
);
@ -166,7 +166,7 @@ macro_rules! outer {
fn f() {
outer!();
} //^^^^^^^^ leftover tokens
} //^^^^^^^^ error: leftover tokens
"#,
)
}

View File

@ -26,7 +26,7 @@ mod tests {
r#"
fn zero() {}
fn f() { zero(1); }
//^^^^^^^ expected 0 arguments, found 1
//^^^^^^^ error: expected 0 arguments, found 1
"#,
);
@ -44,7 +44,7 @@ fn f() { zero(); }
r#"
fn one(arg: u8) {}
fn f() { one(); }
//^^^^^ expected 1 argument, found 0
//^^^^^ error: expected 1 argument, found 0
"#,
);
@ -65,7 +65,7 @@ impl S { fn method(&self) {} }
fn f() {
S::method();
} //^^^^^^^^^^^ expected 1 argument, found 0
} //^^^^^^^^^^^ error: expected 1 argument, found 0
"#,
);
@ -91,7 +91,7 @@ impl S { fn method(&self, arg: u8) {} }
fn f() {
S.method();
} //^^^^^^^^^^ expected 1 argument, found 0
} //^^^^^^^^^^ error: expected 1 argument, found 0
"#,
);
@ -131,7 +131,7 @@ fn f() {
struct Tup(u8, u16);
fn f() {
Tup(0);
} //^^^^^^ expected 2 arguments, found 1
} //^^^^^^ error: expected 2 arguments, found 1
"#,
)
}
@ -143,7 +143,7 @@ fn f() {
enum En { Variant(u8, u16), }
fn f() {
En::Variant(0);
} //^^^^^^^^^^^^^^ expected 2 arguments, found 1
} //^^^^^^^^^^^^^^ error: expected 2 arguments, found 1
"#,
)
}
@ -162,9 +162,9 @@ impl Foo {
fn new() {
Foo::Bar(0);
Foo::Bar(0, 1);
//^^^^^^^^^^^^^^ expected 1 argument, found 2
//^^^^^^^^^^^^^^ error: expected 1 argument, found 2
Foo::Bar();
//^^^^^^^^^^ expected 1 argument, found 0
//^^^^^^^^^^ error: expected 1 argument, found 0
}
}
"#,
@ -185,7 +185,7 @@ fn f() {
unsafe {
fixed(0);
fixed(0, 1);
//^^^^^^^^^^^ expected 1 argument, found 2
//^^^^^^^^^^^ error: expected 1 argument, found 2
varargs(0);
varargs(0, 1);
varargs2();
@ -204,10 +204,10 @@ fn f() {
fn main() {
let f = |()| ();
f();
//^^^ expected 1 argument, found 0
//^^^ error: expected 1 argument, found 0
f(());
f((), ());
//^^^^^^^^^ expected 1 argument, found 2
//^^^^^^^^^ error: expected 1 argument, found 2
}
"#,
)

View File

@ -19,7 +19,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext};
// let a = A { a: 10 };
// ```
pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
let mut message = String::from("Missing structure fields:\n");
let mut message = String::from("missing structure fields:\n");
for field in &d.missed_fields {
format_to!(message, "- {}\n", field);
}
@ -85,7 +85,7 @@ mod tests {
struct S { foo: i32, bar: () }
fn baz(s: S) {
let S { foo: _ } = s;
//^ Missing structure fields:
//^ error: missing structure fields:
//| - bar
}
"#,
@ -323,4 +323,33 @@ fn f() {
"#,
);
}
#[test]
fn import_extern_crate_clash_with_inner_item() {
// This is more of a resolver test, but doesn't really work with the hir_def testsuite.
check_diagnostics(
r#"
//- /lib.rs crate:lib deps:jwt
mod permissions;
use permissions::jwt;
fn f() {
fn inner() {}
jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
}
//- /permissions.rs
pub mod jwt {
pub struct Claims {}
}
//- /jwt/lib.rs crate:jwt
pub struct Claims {
field: u8,
}
"#,
);
}
}

View File

@ -31,9 +31,9 @@ mod tests {
r#"
fn main() {
match () { }
//^^ missing match arm
//^^ error: missing match arm
match (()) { }
//^^^^ missing match arm
//^^^^ error: missing match arm
match () { _ => (), }
match () { () => (), }
@ -49,7 +49,7 @@ fn main() {
r#"
fn main() {
match ((), ()) { }
//^^^^^^^^ missing match arm
//^^^^^^^^ error: missing match arm
match ((), ()) { ((), ()) => (), }
}
@ -63,21 +63,21 @@ fn main() {
r#"
fn test_main() {
match false { }
//^^^^^ missing match arm
//^^^^^ error: missing match arm
match false { true => (), }
//^^^^^ missing match arm
//^^^^^ error: missing match arm
match (false, true) {}
//^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^ error: missing match arm
match (false, true) { (true, true) => (), }
//^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^ error: missing match arm
match (false, true) {
//^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^ error: missing match arm
(false, true) => (),
(false, false) => (),
(true, false) => (),
}
match (false, true) { (true, _x) => (), }
//^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^ error: missing match arm
match false { true => (), false => (), }
match (false, true) {
@ -116,11 +116,11 @@ fn test_main() {
r#"
fn main() {
match (false, ((), false)) {}
//^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^ error: missing match arm
match (false, ((), false)) { (true, ((), true)) => (), }
//^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^ error: missing match arm
match (false, ((), false)) { (true, _) => (), }
//^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^ error: missing match arm
match (false, ((), false)) {
(true, ((), true)) => (),
@ -146,12 +146,12 @@ enum Either { A, B, }
fn main() {
match Either::A { }
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
match Either::B { Either::A => (), }
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
match &Either::B {
//^^^^^^^^^^ missing match arm
//^^^^^^^^^^ error: missing match arm
Either::A => (),
}
@ -174,9 +174,9 @@ enum Either { A(bool), B }
fn main() {
match Either::B { }
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
match Either::B {
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
Either::A(true) => (), Either::B => ()
}
@ -207,7 +207,7 @@ enum Either { A(bool), B(bool, bool) }
fn main() {
match Either::A(false) {
//^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^ error: missing match arm
Either::A(_) => (),
Either::B(false, _) => (),
}
@ -352,7 +352,7 @@ fn main() {
Either::A => (),
}
match loop { break Foo::A } {
//^^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
Either::A => (),
}
match loop { break Foo::A } {
@ -390,19 +390,19 @@ enum Either { A { foo: bool }, B }
fn main() {
let a = Either::A { foo: true };
match a { }
//^ missing match arm
//^ error: missing match arm
match a { Either::A { foo: true } => () }
//^ missing match arm
//^ error: missing match arm
match a {
Either::A { } => (),
//^^^^^^^^^ Missing structure fields:
//^^^^^^^^^ error: missing structure fields:
// | - foo
Either::B => (),
}
match a {
//^ missing match arm
//^ error: missing match arm
Either::A { } => (),
} //^^^^^^^^^ Missing structure fields:
} //^^^^^^^^^ error: missing structure fields:
// | - foo
match a {
@ -431,7 +431,7 @@ enum Either {
fn main() {
let a = Either::A { foo: true, bar: () };
match a {
//^ missing match arm
//^ error: missing match arm
Either::A { bar: (), foo: false } => (),
Either::A { foo: true, bar: () } => (),
}
@ -458,12 +458,12 @@ enum Either {
fn main() {
let a = Either::B;
match a {
//^ missing match arm
//^ error: missing match arm
Either::A { foo: true, .. } => (),
Either::B => (),
}
match a {
//^ missing match arm
//^ error: missing match arm
Either::A { .. } => (),
}
@ -493,14 +493,14 @@ enum Either {
fn main() {
match Either::B {
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
Either::A(true, .., true) => (),
Either::A(true, .., false) => (),
Either::A(false, .., false) => (),
Either::B => (),
}
match Either::B {
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
Either::A(true, .., true) => (),
Either::A(true, .., false) => (),
Either::A(.., true) => (),
@ -537,7 +537,7 @@ fn enum_(never: Never) {
}
fn enum_ref(never: &Never) {
match never {}
//^^^^^ missing match arm
//^^^^^ error: missing match arm
}
fn bang(never: !) {
match never {}
@ -561,7 +561,7 @@ fn main() {
Some(never) => match never {},
}
match Option::<Never>::None {
//^^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
Option::Some(_never) => {},
}
}
@ -575,7 +575,7 @@ fn main() {
r#"
fn main() {
match (false, true, false) {
//^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^ error: missing match arm
(false, ..) => (),
}
}"#,
@ -588,7 +588,7 @@ fn main() {
r#"
fn main() {
match (false, true, false) {
//^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^ error: missing match arm
(.., false) => (),
}
}"#,
@ -601,7 +601,7 @@ fn main() {
r#"
fn main() {
match (false, true, false) {
//^^^^^^^^^^^^^^^^^^^^ missing match arm
//^^^^^^^^^^^^^^^^^^^^ error: missing match arm
(true, .., false) => (),
}
}"#,
@ -614,11 +614,11 @@ fn main() {
r#"struct Foo { a: bool }
fn main(f: Foo) {
match f {}
//^ missing match arm
//^ error: missing match arm
match f { Foo { a: true } => () }
//^ missing match arm
//^ error: missing match arm
match &f { Foo { a: true } => () }
//^^ missing match arm
//^^ error: missing match arm
match f { Foo { a: _ } => () }
match f {
Foo { a: true } => (),
@ -639,9 +639,9 @@ fn main(f: Foo) {
r#"struct Foo(bool);
fn main(f: Foo) {
match f {}
//^ missing match arm
//^ error: missing match arm
match f { Foo(true) => () }
//^ missing match arm
//^ error: missing match arm
match f {
Foo(true) => (),
Foo(false) => (),
@ -657,7 +657,7 @@ fn main(f: Foo) {
r#"struct Foo;
fn main(f: Foo) {
match f {}
//^ missing match arm
//^ error: missing match arm
match f { Foo => () }
}
"#,
@ -670,9 +670,9 @@ fn main(f: Foo) {
r#"struct Foo { foo: bool, bar: bool }
fn main(f: Foo) {
match f { Foo { foo: true, .. } => () }
//^ missing match arm
//^ error: missing match arm
match f {
//^ missing match arm
//^ error: missing match arm
Foo { foo: true, .. } => (),
Foo { bar: false, .. } => ()
}
@ -693,7 +693,7 @@ fn main(f: Foo) {
fn main() {
enum Either { A(bool), B }
match Either::B {
//^^^^^^^^^ missing match arm
//^^^^^^^^^ error: missing match arm
Either::A(true | false) => (),
}
}
@ -715,7 +715,7 @@ fn main(v: S) {
match v { S{..} => {} }
match v { _ => {} }
match v { }
//^ missing match arm
//^ error: missing match arm
}
"#,
);
@ -731,7 +731,7 @@ fn main() {
false => {}
}
match true { _x @ true => {} }
//^^^^ missing match arm
//^^^^ error: missing match arm
}
"#,
);
@ -786,12 +786,12 @@ use lib::E;
fn main() {
match E::A { _ => {} }
match E::A {
//^^^^ missing match arm
//^^^^ error: missing match arm
E::A => {}
E::B => {}
}
match E::A {
//^^^^ missing match arm
//^^^^ error: missing match arm
E::A | E::B => {}
}
}
@ -810,7 +810,7 @@ fn main() {
false => {}
}
match true {
//^^^^ missing match arm
//^^^^ error: missing match arm
true if false => {}
false => {}
}

View File

@ -23,7 +23,7 @@ fn main() {
let x = &5 as *const usize;
unsafe { let y = *x; }
let z = *x;
} //^^ this operation is unsafe and requires an unsafe function or block
} //^^ error: this operation is unsafe and requires an unsafe function or block
"#,
)
}
@ -48,9 +48,9 @@ unsafe fn unsafe_fn() {
fn main() {
unsafe_fn();
//^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block
//^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
HasUnsafe.unsafe_fn();
//^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block
//^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
unsafe {
unsafe_fn();
HasUnsafe.unsafe_fn();
@ -72,7 +72,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 };
fn main() {
let x = STATIC_MUT.a;
//^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block
//^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
unsafe {
let x = STATIC_MUT.a;
}
@ -93,7 +93,7 @@ extern "rust-intrinsic" {
fn main() {
let _ = bitreverse(12);
let _ = floorf32(12.0);
//^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block
//^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
}
"#,
);

View File

@ -119,11 +119,11 @@ struct S { foo: i32, bar: () }
impl S {
fn new() -> S {
S {
//^ Missing structure fields:
//^ 💡 error: missing structure fields:
//| - bar
foo: 92,
baz: 62,
//^^^^^^^ no such field
//^^^^^^^ 💡 error: no such field
}
}
}

View File

@ -49,7 +49,7 @@ mod tests {
check_diagnostics(
r#"
fn test() -> i32 { 123; }
//^^^ remove this semicolon
//^^^ 💡 error: remove this semicolon
"#,
);
}

View File

@ -91,8 +91,8 @@ pub mod iter {
check_diagnostics(
r#"
fn foo() {
let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
let m = [1, 2, 3].iter().filter_map(|x| Some(92)).next();
} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
"#,
);
}
@ -104,7 +104,7 @@ pub mod iter {
fn foo() {
let m = [1, 2, 3]
.iter()
.filter_map(|x| if *x == 2 { Some (4) } else { None })
.filter_map(|x| Some(92))
.len();
}
"#,
@ -118,7 +118,7 @@ fn foo() {
fn foo() {
let m = [1, 2, 3]
.iter()
.filter_map(|x| if *x == 2 { Some (4) } else { None })
.filter_map(|x| Some(92))
.map(|x| x + 2)
.len();
}
@ -133,7 +133,7 @@ fn foo() {
fn foo() {
let m = [1, 2, 3]
.iter()
.filter_map(|x| if *x == 2 { Some (4) } else { None });
.filter_map(|x| Some(92));
let n = m.next();
}
"#,
@ -148,7 +148,7 @@ fn foo() {
use core::iter::Iterator;
use core::option::Option::{self, Some, None};
fn foo() {
let m = [1, 2, 3].iter().$0filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
let m = [1, 2, 3].iter().$0filter_map(|x| Some(92)).next();
}
//- /core/lib.rs crate:core
pub mod option {
@ -171,7 +171,7 @@ pub mod iter {
use core::iter::Iterator;
use core::option::Option::{self, Some, None};
fn foo() {
let m = [1, 2, 3].iter().find_map(|x| if *x == 2 { Some (4) } else { None });
let m = [1, 2, 3].iter().find_map(|x| Some(92));
}
"#,
)

View File

@ -14,32 +14,29 @@ use text_edit::TextEdit;
use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
#[derive(Debug)]
pub(crate) struct UnlinkedFile {
pub(crate) file: FileId,
}
// Diagnostic: unlinked-file
//
// This diagnostic is shown for files that are not included in any crate, or files that are part of
// crates rust-analyzer failed to discover. The file will not have IDE features available.
pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic {
pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, acc: &mut Vec<Diagnostic>, file_id: FileId) {
// Limit diagnostic to the first few characters in the file. This matches how VS Code
// renders it with the full span, but on other editors, and is less invasive.
let range = ctx.sema.db.parse(d.file).syntax_node().text_range();
let range = ctx.sema.db.parse(file_id).syntax_node().text_range();
// FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`.
let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
Diagnostic::new("unlinked-file", "file not included in module tree", range)
.with_fixes(fixes(ctx, d))
acc.push(
Diagnostic::new("unlinked-file", "file not included in module tree", range)
.with_fixes(fixes(ctx, file_id)),
);
}
fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> {
fn fixes(ctx: &DiagnosticsContext, file_id: FileId) -> Option<Vec<Assist>> {
// If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file,
// suggest that as a fix.
let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(d.file));
let our_path = source_root.path_for_file(&d.file)?;
let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id));
let our_path = source_root.path_for_file(&file_id)?;
let module_name = our_path.name_and_extension()?.0;
// Candidates to look for:
@ -68,7 +65,7 @@ fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> {
}
if module.origin.file_id() == Some(*parent_id) {
return make_fixes(ctx.sema.db, *parent_id, module_name, d.file);
return make_fixes(ctx.sema.db, *parent_id, module_name, file_id);
}
}
}

View File

@ -25,7 +25,7 @@ mod tests {
//- /main.rs crate:main deps:core
extern crate core;
extern crate doesnotexist;
//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
//- /lib.rs crate:core
"#,
);
@ -38,7 +38,7 @@ extern crate core;
r#"
//- /lib.rs
extern crate doesnotexist;
//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
// Should not error.
extern crate self as foo;
struct Foo;

View File

@ -30,7 +30,7 @@ mod tests {
r#"
use does_exist;
use does_not_exist;
//^^^^^^^^^^^^^^ unresolved import
//^^^^^^^^^^^^^^ error: unresolved import
mod does_exist {}
"#,
@ -43,18 +43,18 @@ mod does_exist {}
check_diagnostics(
r#"
use does_exist::{Exists, DoesntExist};
//^^^^^^^^^^^ unresolved import
//^^^^^^^^^^^ error: unresolved import
use {does_not_exist::*, does_exist};
//^^^^^^^^^^^^^^^^^ unresolved import
//^^^^^^^^^^^^^^^^^ error: unresolved import
use does_not_exist::{
a,
//^ unresolved import
//^ error: unresolved import
b,
//^ unresolved import
//^ error: unresolved import
c,
//^ unresolved import
//^ error: unresolved import
};
mod does_exist {
@ -71,18 +71,18 @@ mod does_exist {
//- /main.rs crate:main
mod a {
extern crate doesnotexist;
//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
// Should not error, since we already errored for the missing crate.
use doesnotexist::{self, bla, *};
use crate::doesnotexist;
//^^^^^^^^^^^^^^^^^^^ unresolved import
//^^^^^^^^^^^^^^^^^^^ error: unresolved import
}
mod m {
use super::doesnotexist;
//^^^^^^^^^^^^^^^^^^^ unresolved import
//^^^^^^^^^^^^^^^^^^^ error: unresolved import
}
"#,
);

View File

@ -40,7 +40,7 @@ mod tests {
r#"
fn f() {
m!();
} //^ unresolved macro `m!`
} //^ error: unresolved macro `m!`
"#,
);
@ -51,7 +51,7 @@ fn f() {
check_diagnostics(
r#"
foo::bar!(92);
//^^^ unresolved macro `foo::bar!`
//^^^ error: unresolved macro `foo::bar!`
"#,
);
}
@ -63,7 +63,7 @@ foo::bar!(92);
macro_rules! m { () => {} }
m!(); m2!();
//^^ unresolved macro `self::m2!`
//^^ error: unresolved macro `self::m2!`
"#,
);
}
@ -77,7 +77,7 @@ mod mac {
macro_rules! m { () => {} } }
self::m!(); self::m2!();
//^^ unresolved macro `self::m2!`
//^^ error: unresolved macro `self::m2!`
"#,
);
}

View File

@ -50,7 +50,7 @@ mod tests {
//- /lib.rs
mod foo;
mod bar;
//^^^^^^^^ unresolved module
//^^^^^^^^ 💡 error: unresolved module
mod baz {}
//- /foo.rs
"#,

View File

@ -0,0 +1,148 @@
use ide_db::{base_db::FileId, source_change::SourceChange};
use itertools::Itertools;
use syntax::{ast, AstNode, SyntaxNode, TextRange};
use text_edit::TextEdit;
use crate::{fix, Diagnostic, Severity};
// Diagnostic: unnecessary-braces
//
// Diagnostic for unnecessary braces in `use` items.
pub(crate) fn useless_braces(
acc: &mut Vec<Diagnostic>,
file_id: FileId,
node: &SyntaxNode,
) -> Option<()> {
let use_tree_list = ast::UseTreeList::cast(node.clone())?;
if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
// If there is a comment inside the bracketed `use`,
// assume it is a commented out module path and don't show diagnostic.
if use_tree_list.has_inner_comment() {
return Some(());
}
let use_range = use_tree_list.syntax().text_range();
let edit = remove_braces(&single_use_tree).unwrap_or_else(|| {
let to_replace = single_use_tree.syntax().text().to_string();
let mut edit_builder = TextEdit::builder();
edit_builder.delete(use_range);
edit_builder.insert(use_range.start(), to_replace);
edit_builder.finish()
});
acc.push(
Diagnostic::new(
"unnecessary-braces",
"Unnecessary braces in use statement".to_string(),
use_range,
)
.severity(Severity::WeakWarning)
.with_fixes(Some(vec![fix(
"remove_braces",
"Remove unnecessary braces",
SourceChange::from_text_edit(file_id, edit),
use_range,
)])),
);
}
Some(())
}
fn remove_braces(single_use_tree: &ast::UseTree) -> Option<TextEdit> {
let use_tree_list_node = single_use_tree.syntax().parent()?;
if single_use_tree.path()?.segment()?.self_token().is_some() {
let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
let end = use_tree_list_node.text_range().end();
return Some(TextEdit::delete(TextRange::new(start, end)));
}
None
}
#[cfg(test)]
mod tests {
use crate::tests::{check_diagnostics, check_fix};
#[test]
fn test_check_unnecessary_braces_in_use_statement() {
check_diagnostics(
r#"
use a;
use a::{c, d::e};
mod a {
mod c {}
mod d {
mod e {}
}
}
"#,
);
check_diagnostics(
r#"
use a;
use a::{
c,
// d::e
};
mod a {
mod c {}
mod d {
mod e {}
}
}
"#,
);
check_fix(
r#"
mod b {}
use {$0b};
"#,
r#"
mod b {}
use b;
"#,
);
check_fix(
r#"
mod b {}
use {b$0};
"#,
r#"
mod b {}
use b;
"#,
);
check_fix(
r#"
mod a { mod c {} }
use a::{c$0};
"#,
r#"
mod a { mod c {} }
use a::c;
"#,
);
check_fix(
r#"
mod a {}
use a::{self$0};
"#,
r#"
mod a {}
use a;
"#,
);
check_fix(
r#"
mod a { mod c {} mod d { mod e {} } }
use a::{c, d::{e$0}};
"#,
r#"
mod a { mod c {} mod d { mod e {} } }
use a::{c, d::e};
"#,
);
}
}

View File

@ -37,15 +37,17 @@ mod handlers {
pub(crate) mod remove_this_semicolon;
pub(crate) mod replace_filter_map_next_with_find_map;
pub(crate) mod unimplemented_builtin_macro;
pub(crate) mod unlinked_file;
pub(crate) mod unresolved_extern_crate;
pub(crate) mod unresolved_import;
pub(crate) mod unresolved_macro_call;
pub(crate) mod unresolved_module;
pub(crate) mod unresolved_proc_macro;
}
mod field_shorthand;
// The handlers bellow are unusual, the implement the diagnostics as well.
pub(crate) mod field_shorthand;
pub(crate) mod useless_braces;
pub(crate) mod unlinked_file;
}
use hir::{diagnostics::AnyDiagnostic, Semantics};
use ide_db::{
@ -55,15 +57,8 @@ use ide_db::{
source_change::SourceChange,
RootDatabase,
};
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{
ast::{self, AstNode},
SyntaxNode, TextRange,
};
use text_edit::TextEdit;
use crate::handlers::unlinked_file::UnlinkedFile;
use syntax::{ast::AstNode, TextRange};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DiagnosticCode(pub &'static str);
@ -123,6 +118,8 @@ impl Diagnostic {
#[derive(Debug, Copy, Clone)]
pub enum Severity {
Error,
// We don't actually emit this one yet, but we should at some point.
// Warning,
WeakWarning,
}
@ -157,21 +154,20 @@ pub fn diagnostics(
);
for node in parse.tree().syntax().descendants() {
check_unnecessary_braces_in_use_statement(&mut res, file_id, &node);
field_shorthand::check(&mut res, file_id, &node);
handlers::useless_braces::useless_braces(&mut res, file_id, &node);
handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
}
let mut diags = Vec::new();
let module = sema.to_module_def(file_id);
if let Some(m) = module {
m.diagnostics(db, &mut diags)
}
let ctx = DiagnosticsContext { config, sema, resolve };
if module.is_none() {
let d = UnlinkedFile { file: file_id };
let d = handlers::unlinked_file::unlinked_file(&ctx, &d);
res.push(d)
handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
}
let mut diags = Vec::new();
if let Some(m) = module {
m.diagnostics(db, &mut diags)
}
for diag in diags {
@ -211,61 +207,6 @@ pub fn diagnostics(
res
}
fn check_unnecessary_braces_in_use_statement(
acc: &mut Vec<Diagnostic>,
file_id: FileId,
node: &SyntaxNode,
) -> Option<()> {
let use_tree_list = ast::UseTreeList::cast(node.clone())?;
if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
// If there is a comment inside the bracketed `use`,
// assume it is a commented out module path and don't show diagnostic.
if use_tree_list.has_inner_comment() {
return Some(());
}
let use_range = use_tree_list.syntax().text_range();
let edit =
text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
.unwrap_or_else(|| {
let to_replace = single_use_tree.syntax().text().to_string();
let mut edit_builder = TextEdit::builder();
edit_builder.delete(use_range);
edit_builder.insert(use_range.start(), to_replace);
edit_builder.finish()
});
acc.push(
Diagnostic::new(
"unnecessary-braces",
"Unnecessary braces in use statement".to_string(),
use_range,
)
.severity(Severity::WeakWarning)
.with_fixes(Some(vec![fix(
"remove_braces",
"Remove unnecessary braces",
SourceChange::from_text_edit(file_id, edit),
use_range,
)])),
);
}
Some(())
}
fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
single_use_tree: &ast::UseTree,
) -> Option<TextEdit> {
let use_tree_list_node = single_use_tree.syntax().parent()?;
if single_use_tree.path()?.segment()?.self_token().is_some() {
let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
let end = use_tree_list_node.text_range().end();
return Some(TextEdit::delete(TextRange::new(start, end)));
}
None
}
fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
let mut res = unresolved_fix(id, label, target);
res.source_change = Some(source_change);
@ -294,7 +235,7 @@ mod tests {
use stdx::trim_indent;
use test_utils::{assert_eq_text, extract_annotations};
use crate::DiagnosticsConfig;
use crate::{DiagnosticsConfig, Severity};
/// Takes a multi-file input fixture with annotated cursor positions,
/// and checks that:
@ -390,96 +331,28 @@ mod tests {
super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
let expected = extract_annotations(&*db.file_text(file_id));
let mut actual =
diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>();
let mut actual = diagnostics
.into_iter()
.map(|d| {
let mut annotation = String::new();
if let Some(fixes) = &d.fixes {
assert!(!fixes.is_empty());
annotation.push_str("💡 ")
}
annotation.push_str(match d.severity {
Severity::Error => "error",
Severity::WeakWarning => "weak",
});
annotation.push_str(": ");
annotation.push_str(&d.message);
(d.range, annotation)
})
.collect::<Vec<_>>();
actual.sort_by_key(|(range, _)| range.start());
assert_eq!(expected, actual);
}
}
#[test]
fn test_check_unnecessary_braces_in_use_statement() {
check_diagnostics(
r#"
use a;
use a::{c, d::e};
mod a {
mod c {}
mod d {
mod e {}
}
}
"#,
);
check_diagnostics(
r#"
use a;
use a::{
c,
// d::e
};
mod a {
mod c {}
mod d {
mod e {}
}
}
"#,
);
check_fix(
r"
mod b {}
use {$0b};
",
r"
mod b {}
use b;
",
);
check_fix(
r"
mod b {}
use {b$0};
",
r"
mod b {}
use b;
",
);
check_fix(
r"
mod a { mod c {} }
use a::{c$0};
",
r"
mod a { mod c {} }
use a::c;
",
);
check_fix(
r"
mod a {}
use a::{self$0};
",
r"
mod a {}
use a;
",
);
check_fix(
r"
mod a { mod c {} mod d { mod e {} } }
use a::{c, d::{e$0}};
",
r"
mod a { mod c {} mod d { mod e {} } }
use a::{c, d::e};
",
);
}
#[test]
fn test_disabled_diagnostics() {
let mut config = DiagnosticsConfig::default();
@ -498,33 +371,4 @@ mod a {
);
assert!(!diagnostics.is_empty());
}
#[test]
fn import_extern_crate_clash_with_inner_item() {
// This is more of a resolver test, but doesn't really work with the hir_def testsuite.
check_diagnostics(
r#"
//- /lib.rs crate:lib deps:jwt
mod permissions;
use permissions::jwt;
fn f() {
fn inner() {}
jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
}
//- /permissions.rs
pub mod jwt {
pub struct Claims {}
}
//- /jwt/lib.rs crate:jwt
pub struct Claims {
field: u8,
}
"#,
);
}
}