1
- use hir:: InFile ;
2
- use itertools:: Itertools ;
3
- use syntax:: { ast, AstNode } ;
1
+ use hir:: { db:: ExpandDatabase , Const , Function , HasSource , TypeAlias } ;
2
+ use syntax:: ast;
4
3
5
- use crate :: { adjusted_display_range , Diagnostic , DiagnosticCode , DiagnosticsContext } ;
4
+ use crate :: { Diagnostic , DiagnosticCode , DiagnosticsContext } ;
6
5
7
6
// Diagnostic: trait-impl-reduntant-assoc_item
8
7
//
@@ -11,26 +10,53 @@ pub(crate) fn trait_impl_reduntant_assoc_item(
11
10
ctx : & DiagnosticsContext < ' _ > ,
12
11
d : & hir:: TraitImplReduntantAssocItems ,
13
12
) -> Diagnostic {
14
- let reduntant = d. reduntant . iter ( ) . format_with ( ", " , |( name, item) , f| {
15
- f ( & match * item {
16
- hir:: AssocItem :: Function ( _) => "`fn " ,
17
- hir:: AssocItem :: Const ( _) => "`const " ,
18
- hir:: AssocItem :: TypeAlias ( _) => "`type " ,
19
- } ) ?;
20
- f ( & name. display ( ctx. sema . db ) ) ?;
21
- f ( & "`" )
22
- } ) ;
13
+ let name = d. assoc_item . 0 . clone ( ) ;
14
+ let assoc_item = d. assoc_item . 1 ;
15
+ let db = ctx. sema . db ;
16
+
17
+ let root = ctx. sema . db . parse_or_expand ( d. file_id ) ;
18
+ let range = root. text_range ( ) ;
19
+ let impl_ = d. impl_ . to_node ( & root) ;
20
+ let trait_name = if let Some ( trait_name) = trait_name ( ctx, impl_) {
21
+ trait_name
22
+ } else {
23
+ String :: from ( "{unkown}" )
24
+ } ;
25
+
26
+ let ( reduntant_item_name, diagnostic_range) = match assoc_item {
27
+ hir:: AssocItem :: Function ( id) => (
28
+ format ! ( "`fn {}`" , name. display( db) ) ,
29
+ Function :: from ( id) . source ( db) . map ( |it| it. syntax ( ) . value . text_range ( ) ) . unwrap_or ( range) ,
30
+ ) ,
31
+ hir:: AssocItem :: Const ( id) => (
32
+ format ! ( "`const {}`" , name. display( db) ) ,
33
+ Const :: from ( id) . source ( db) . map ( |it| it. syntax ( ) . value . text_range ( ) ) . unwrap_or ( range) ,
34
+ ) ,
35
+ hir:: AssocItem :: TypeAlias ( id) => (
36
+ format ! ( "`type {}`" , name. display( db) ) ,
37
+ TypeAlias :: from ( id)
38
+ . source ( db)
39
+ . map ( |it| it. syntax ( ) . value . text_range ( ) )
40
+ . unwrap_or ( range) ,
41
+ ) ,
42
+ } ;
43
+
23
44
Diagnostic :: new (
24
45
DiagnosticCode :: RustcHardError ( "E0407" ) ,
25
- format ! ( "{reduntant} is not a member of trait" ) ,
26
- adjusted_display_range :: < ast:: Impl > (
27
- ctx,
28
- InFile { file_id : d. file_id , value : d. impl_ . syntax_node_ptr ( ) } ,
29
- & |impl_| impl_. trait_ ( ) . map ( |t| t. syntax ( ) . text_range ( ) ) ,
30
- ) ,
46
+ format ! ( "{reduntant_item_name} is not a member of trait `{trait_name}`" ) ,
47
+ diagnostic_range,
31
48
)
32
49
}
33
50
51
+ fn trait_name ( ctx : & DiagnosticsContext < ' _ > , impl_ : ast:: Impl ) -> Option < String > {
52
+ if let ast:: Type :: PathType ( trait_path) = impl_. trait_ ( ) ? {
53
+ let trait_type = ctx. sema . resolve_trait ( & trait_path. path ( ) ?) ?;
54
+ Some ( trait_type. name ( ctx. sema . db ) . as_text ( ) ?. to_string ( ) )
55
+ } else {
56
+ None
57
+ }
58
+ }
59
+
34
60
#[ cfg( test) ]
35
61
mod tests {
36
62
use crate :: tests:: check_diagnostics;
@@ -40,14 +66,20 @@ mod tests {
40
66
check_diagnostics (
41
67
r#"
42
68
trait Marker {
69
+ const FLAG: bool = false;
43
70
fn boo();
71
+ fn foo () {}
44
72
}
45
73
struct Foo;
46
74
impl Marker for Foo {
47
- //^^^^^^ error: `type T`, `const FLAG`, `fn bar` is not a member of trait
48
75
type T = i32;
49
- const FLAG: bool = false;
76
+ //^^^^^^^^^^^^^ error: `type T` is not a member of trait `Marker`
77
+
78
+ const FLAG: bool = true;
79
+
50
80
fn bar() {}
81
+ //^^^^^^^^^^^ error: `fn bar` is not a member of trait `Marker`
82
+
51
83
fn boo() {}
52
84
}
53
85
"# ,
0 commit comments