Skip to content

Commit 52df627

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

File tree

1 file changed

+148
-5
lines changed

1 file changed

+148
-5
lines changed

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

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use hir::{EditionedFileId, 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::{AstNode, SyntaxKind, TextRange, TextSize, ast::HasVisibility};
44

55
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
66

77
// Diagnostic: private-field
88
//
99
// This diagnostic is triggered if the accessed field is not visible from the current module.
1010
pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) -> Diagnostic {
11-
// FIXME: add quickfix
1211
Diagnostic::new_with_syntax_node_ptr(
1312
ctx,
1413
DiagnosticCode::RustcHardError("E0616"),
@@ -50,10 +49,24 @@ pub(crate) fn field_is_private_fixes(
5049
source.with_value(visibility.syntax()).original_file_range_opt(sema.db)?.0
5150
}
5251
None => {
53-
let (range, _) = source.syntax().original_file_range_opt(sema.db)?;
52+
let field_syntax = source.value.syntax();
53+
let vis_before = field_syntax.children_with_tokens().find(|it| {
54+
!matches!(
55+
it.kind(),
56+
SyntaxKind::WHITESPACE | SyntaxKind::COMMENT | SyntaxKind::ATTR
57+
)
58+
})?;
59+
60+
// Get the text range of the first non-comment token relative to the field node
61+
let relative_offset =
62+
vis_before.text_range().start() - field_syntax.text_range().start();
63+
let (field_range, _) = source.syntax().original_file_range_opt(sema.db)?;
64+
65+
let absolute_offset = field_range.range.start() + relative_offset;
66+
5467
FileRange {
55-
file_id: range.file_id,
56-
range: TextRange::at(range.range.start(), TextSize::new(0)),
68+
file_id: field_range.file_id,
69+
range: TextRange::at(absolute_offset, TextSize::new(0)),
5770
}
5871
}
5972
};
@@ -225,6 +238,136 @@ pub mod foo {
225238
226239
fn foo(v: foo::bar::Struct) {
227240
v.field;
241+
}
242+
"#,
243+
);
244+
}
245+
246+
#[test]
247+
fn change_visibility_of_field_with_doc_comment() {
248+
check_fix(
249+
r#"
250+
pub mod foo {
251+
pub struct Foo {
252+
/// This is a doc comment
253+
bar: u32,
254+
}
255+
}
256+
257+
fn main() {
258+
let x = foo::Foo { bar: 0 };
259+
x.bar$0;
260+
}
261+
"#,
262+
r#"
263+
pub mod foo {
264+
pub struct Foo {
265+
/// This is a doc comment
266+
pub(crate) bar: u32,
267+
}
268+
}
269+
270+
fn main() {
271+
let x = foo::Foo { bar: 0 };
272+
x.bar;
273+
}
274+
"#,
275+
);
276+
}
277+
278+
#[test]
279+
fn change_visibility_of_field_with_line_comment() {
280+
check_fix(
281+
r#"
282+
pub mod foo {
283+
pub struct Foo {
284+
// This is a line comment
285+
bar: u32,
286+
}
287+
}
288+
289+
fn main() {
290+
let x = foo::Foo { bar: 0 };
291+
x.bar$0;
292+
}
293+
"#,
294+
r#"
295+
pub mod foo {
296+
pub struct Foo {
297+
// This is a line comment
298+
pub(crate) bar: u32,
299+
}
300+
}
301+
302+
fn main() {
303+
let x = foo::Foo { bar: 0 };
304+
x.bar;
305+
}
306+
"#,
307+
);
308+
}
309+
310+
#[test]
311+
fn change_visibility_of_field_with_multiple_doc_comments() {
312+
check_fix(
313+
r#"
314+
pub mod foo {
315+
pub struct Foo {
316+
/// First line
317+
/// Second line
318+
bar: u32,
319+
}
320+
}
321+
322+
fn main() {
323+
let x = foo::Foo { bar: 0 };
324+
x.bar$0;
325+
}
326+
"#,
327+
r#"
328+
pub mod foo {
329+
pub struct Foo {
330+
/// First line
331+
/// Second line
332+
pub(crate) bar: u32,
333+
}
334+
}
335+
336+
fn main() {
337+
let x = foo::Foo { bar: 0 };
338+
x.bar;
339+
}
340+
"#,
341+
);
342+
}
343+
344+
#[test]
345+
fn change_visibility_of_field_with_attr_and_comment() {
346+
check_fix(
347+
r#"
348+
mod foo {
349+
pub struct Foo {
350+
#[rustfmt::skip]
351+
/// First line
352+
/// Second line
353+
bar: u32,
354+
}
355+
}
356+
fn main() {
357+
foo::Foo { $0bar: 42 };
358+
}
359+
"#,
360+
r#"
361+
mod foo {
362+
pub struct Foo {
363+
#[rustfmt::skip]
364+
/// First line
365+
/// Second line
366+
pub(crate) bar: u32,
367+
}
368+
}
369+
fn main() {
370+
foo::Foo { bar: 42 };
228371
}
229372
"#,
230373
);

0 commit comments

Comments
 (0)