Skip to content

Commit 1700dd3

Browse files
Add visibility diagnostics for private fields to the correct location
1 parent f3cbd0e commit 1700dd3

File tree

1 file changed

+150
-10
lines changed

1 file changed

+150
-10
lines changed

crates/ide-diagnostics/src/handlers/private_field.rs

Lines changed: 150 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
use hir::{EditionedFileId, FileRange, HasCrate, HasSource, Semantics};
1+
use hir::{EditionedFileId, FieldSource, FileRange, HasCrate, HasSource, Semantics};
22
use ide_db::{RootDatabase, assists::Assist, source_change::SourceChange, text_edit::TextEdit};
3-
use syntax::{AstNode, TextRange, TextSize, ast::HasVisibility};
3+
use syntax::{
4+
AstNode, TextRange,
5+
ast::{HasName as _, HasVisibility},
6+
};
47

58
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
69

710
// Diagnostic: private-field
811
//
912
// This diagnostic is triggered if the accessed field is not visible from the current module.
1013
pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) -> Diagnostic {
11-
// FIXME: add quickfix
1214
Diagnostic::new_with_syntax_node_ptr(
1315
ctx,
1416
DiagnosticCode::RustcHardError("E0616"),
@@ -40,8 +42,8 @@ pub(crate) fn field_is_private_fixes(
4042

4143
let source = private_field.source(sema.db)?;
4244
let existing_visibility = match &source.value {
43-
hir::FieldSource::Named(it) => it.visibility(),
44-
hir::FieldSource::Pos(it) => it.visibility(),
45+
FieldSource::Named(it) => it.visibility(),
46+
FieldSource::Pos(it) => it.visibility(),
4547
};
4648
let range = match existing_visibility {
4749
Some(visibility) => {
@@ -50,11 +52,19 @@ pub(crate) fn field_is_private_fixes(
5052
source.with_value(visibility.syntax()).original_file_range_opt(sema.db)?.0
5153
}
5254
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-
}
55+
let (range, _) = source
56+
.map(|it| {
57+
Some(match it {
58+
FieldSource::Named(it) => {
59+
it.unsafe_token().or(it.name()?.ident_token())?.text_range()
60+
}
61+
FieldSource::Pos(it) => it.ty()?.syntax().text_range(),
62+
})
63+
})
64+
.transpose()?
65+
.original_node_file_range_opt(sema.db)?;
66+
67+
FileRange { file_id: range.file_id, range: TextRange::empty(range.range.start()) }
5868
}
5969
};
6070
let source_change = SourceChange::from_text_edit(
@@ -225,6 +235,136 @@ pub mod foo {
225235
226236
fn foo(v: foo::bar::Struct) {
227237
v.field;
238+
}
239+
"#,
240+
);
241+
}
242+
243+
#[test]
244+
fn change_visibility_of_field_with_doc_comment() {
245+
check_fix(
246+
r#"
247+
pub mod foo {
248+
pub struct Foo {
249+
/// This is a doc comment
250+
bar: u32,
251+
}
252+
}
253+
254+
fn main() {
255+
let x = foo::Foo { bar: 0 };
256+
x.bar$0;
257+
}
258+
"#,
259+
r#"
260+
pub mod foo {
261+
pub struct Foo {
262+
/// This is a doc comment
263+
pub(crate) bar: u32,
264+
}
265+
}
266+
267+
fn main() {
268+
let x = foo::Foo { bar: 0 };
269+
x.bar;
270+
}
271+
"#,
272+
);
273+
}
274+
275+
#[test]
276+
fn change_visibility_of_field_with_line_comment() {
277+
check_fix(
278+
r#"
279+
pub mod foo {
280+
pub struct Foo {
281+
// This is a line comment
282+
bar: u32,
283+
}
284+
}
285+
286+
fn main() {
287+
let x = foo::Foo { bar: 0 };
288+
x.bar$0;
289+
}
290+
"#,
291+
r#"
292+
pub mod foo {
293+
pub struct Foo {
294+
// This is a line comment
295+
pub(crate) bar: u32,
296+
}
297+
}
298+
299+
fn main() {
300+
let x = foo::Foo { bar: 0 };
301+
x.bar;
302+
}
303+
"#,
304+
);
305+
}
306+
307+
#[test]
308+
fn change_visibility_of_field_with_multiple_doc_comments() {
309+
check_fix(
310+
r#"
311+
pub mod foo {
312+
pub struct Foo {
313+
/// First line
314+
/// Second line
315+
bar: u32,
316+
}
317+
}
318+
319+
fn main() {
320+
let x = foo::Foo { bar: 0 };
321+
x.bar$0;
322+
}
323+
"#,
324+
r#"
325+
pub mod foo {
326+
pub struct Foo {
327+
/// First line
328+
/// Second line
329+
pub(crate) bar: u32,
330+
}
331+
}
332+
333+
fn main() {
334+
let x = foo::Foo { bar: 0 };
335+
x.bar;
336+
}
337+
"#,
338+
);
339+
}
340+
341+
#[test]
342+
fn change_visibility_of_field_with_attr_and_comment() {
343+
check_fix(
344+
r#"
345+
mod foo {
346+
pub struct Foo {
347+
#[rustfmt::skip]
348+
/// First line
349+
/// Second line
350+
bar: u32,
351+
}
352+
}
353+
fn main() {
354+
foo::Foo { $0bar: 42 };
355+
}
356+
"#,
357+
r#"
358+
mod foo {
359+
pub struct Foo {
360+
#[rustfmt::skip]
361+
/// First line
362+
/// Second line
363+
pub(crate) bar: u32,
364+
}
365+
}
366+
fn main() {
367+
foo::Foo { bar: 42 };
228368
}
229369
"#,
230370
);

0 commit comments

Comments
 (0)