1
- use crate :: { Diagnostic , DiagnosticCode , DiagnosticsContext } ;
1
+ use hir:: { EditionedFileId , FileRange , HasCrate , HasSource , Semantics } ;
2
+ use ide_db:: { RootDatabase , assists:: Assist , source_change:: SourceChange , text_edit:: TextEdit } ;
3
+ use syntax:: { AstNode , TextRange , TextSize , ast:: HasVisibility } ;
4
+
5
+ use crate :: { Diagnostic , DiagnosticCode , DiagnosticsContext , fix} ;
2
6
3
7
// Diagnostic: private-field
4
8
//
@@ -16,11 +20,59 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
16
20
d. expr . map ( |it| it. into ( ) ) ,
17
21
)
18
22
. stable ( )
23
+ . with_fixes ( field_is_private_fixes (
24
+ & ctx. sema ,
25
+ d. expr . file_id . original_file ( ctx. sema . db ) ,
26
+ d. field ,
27
+ ctx. sema . original_range ( d. expr . to_node ( ctx. sema . db ) . syntax ( ) ) . range ,
28
+ ) )
29
+ }
30
+
31
+ pub ( crate ) fn field_is_private_fixes (
32
+ sema : & Semantics < ' _ , RootDatabase > ,
33
+ usage_file_id : EditionedFileId ,
34
+ private_field : hir:: Field ,
35
+ fix_range : TextRange ,
36
+ ) -> Option < Vec < Assist > > {
37
+ let def_crate = private_field. krate ( sema. db ) ;
38
+ let usage_crate = sema. file_to_module_def ( usage_file_id. file_id ( sema. db ) ) ?. krate ( ) ;
39
+ let mut visibility_text = if usage_crate == def_crate { "pub(crate) " } else { "pub " } ;
40
+
41
+ let source = private_field. source ( sema. db ) ?;
42
+ let existing_visibility = match & source. value {
43
+ hir:: FieldSource :: Named ( it) => it. visibility ( ) ,
44
+ hir:: FieldSource :: Pos ( it) => it. visibility ( ) ,
45
+ } ;
46
+ let range = match existing_visibility {
47
+ Some ( visibility) => {
48
+ // If there is an existing visibility, don't insert whitespace after.
49
+ visibility_text = visibility_text. trim_end ( ) ;
50
+ source. with_value ( visibility. syntax ( ) ) . original_file_range_opt ( sema. db ) ?. 0
51
+ }
52
+ None => {
53
+ let ( range, _) = source. syntax ( ) . original_file_range_opt ( sema. db ) ?;
54
+ FileRange {
55
+ file_id : range. file_id ,
56
+ range : TextRange :: at ( range. range . start ( ) , TextSize :: new ( 0 ) ) ,
57
+ }
58
+ }
59
+ } ;
60
+ let source_change = SourceChange :: from_text_edit (
61
+ range. file_id . file_id ( sema. db ) ,
62
+ TextEdit :: replace ( range. range , visibility_text. into ( ) ) ,
63
+ ) ;
64
+
65
+ Some ( vec ! [ fix(
66
+ "increase_field_visibility" ,
67
+ "Increase field visibility" ,
68
+ source_change,
69
+ fix_range,
70
+ ) ] )
19
71
}
20
72
21
73
#[ cfg( test) ]
22
74
mod tests {
23
- use crate :: tests:: check_diagnostics;
75
+ use crate :: tests:: { check_diagnostics, check_fix } ;
24
76
25
77
#[ test]
26
78
fn private_field ( ) {
@@ -29,7 +81,7 @@ mod tests {
29
81
mod module { pub struct Struct { field: u32 } }
30
82
fn main(s: module::Struct) {
31
83
s.field;
32
- //^^^^^^^ error: field `field` of `Struct` is private
84
+ //^^^^^^^ 💡 error: field `field` of `Struct` is private
33
85
}
34
86
"# ,
35
87
) ;
@@ -42,7 +94,7 @@ fn main(s: module::Struct) {
42
94
mod module { pub struct Struct(u32); }
43
95
fn main(s: module::Struct) {
44
96
s.0;
45
- //^^^ error: field `0` of `Struct` is private
97
+ //^^^ 💡 error: field `0` of `Struct` is private
46
98
}
47
99
"# ,
48
100
) ;
@@ -113,4 +165,68 @@ fn main() {
113
165
"# ,
114
166
) ;
115
167
}
168
+
169
+ #[ test]
170
+ fn change_visibility_fix ( ) {
171
+ check_fix (
172
+ r#"
173
+ pub mod foo {
174
+ pub mod bar {
175
+ pub struct Struct {
176
+ field: i32,
177
+ }
178
+ }
179
+ }
180
+
181
+ fn foo(v: foo::bar::Struct) {
182
+ v.field$0;
183
+ }
184
+ "# ,
185
+ r#"
186
+ pub mod foo {
187
+ pub mod bar {
188
+ pub struct Struct {
189
+ pub(crate) field: i32,
190
+ }
191
+ }
192
+ }
193
+
194
+ fn foo(v: foo::bar::Struct) {
195
+ v.field;
196
+ }
197
+ "# ,
198
+ ) ;
199
+ }
200
+
201
+ #[ test]
202
+ fn change_visibility_with_existing_visibility ( ) {
203
+ check_fix (
204
+ r#"
205
+ pub mod foo {
206
+ pub mod bar {
207
+ pub struct Struct {
208
+ pub(super) field: i32,
209
+ }
210
+ }
211
+ }
212
+
213
+ fn foo(v: foo::bar::Struct) {
214
+ v.field$0;
215
+ }
216
+ "# ,
217
+ r#"
218
+ pub mod foo {
219
+ pub mod bar {
220
+ pub struct Struct {
221
+ pub(crate) field: i32,
222
+ }
223
+ }
224
+ }
225
+
226
+ fn foo(v: foo::bar::Struct) {
227
+ v.field;
228
+ }
229
+ "# ,
230
+ ) ;
231
+ }
116
232
}
0 commit comments