Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 0395328

Browse files
committed
Auto merge of rust-lang#16058 - Veykril:macro-diagnostics, r=Veykril
fix: Smaller spans for unresolved field and method diagnostics
2 parents 9e82ab5 + b1a8f83 commit 0395328

File tree

7 files changed

+99
-18
lines changed

7 files changed

+99
-18
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hir-expand/src/files.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,21 @@ impl InFile<TextRange> {
314314
}
315315
}
316316

317+
pub fn original_node_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange {
318+
match self.file_id.repr() {
319+
HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value },
320+
HirFileIdRepr::MacroFile(mac_file) => {
321+
match ExpansionInfo::new(db, mac_file).map_node_range_up(db, self.value) {
322+
Some((it, SyntaxContextId::ROOT)) => it,
323+
_ => {
324+
let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
325+
loc.kind.original_call_range(db)
326+
}
327+
}
328+
}
329+
}
330+
}
331+
317332
pub fn original_node_file_range_opt(
318333
self,
319334
db: &dyn db::ExpandDatabase,

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use ide_db::{
88
use syntax::{ast, AstNode, AstPtr};
99
use text_edit::TextEdit;
1010

11-
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
11+
use crate::{adjusted_display_range_new, Diagnostic, DiagnosticCode, DiagnosticsContext};
1212

1313
// Diagnostic: unresolved-field
1414
//
@@ -22,15 +22,24 @@ pub(crate) fn unresolved_field(
2222
} else {
2323
""
2424
};
25-
Diagnostic::new_with_syntax_node_ptr(
26-
ctx,
25+
Diagnostic::new(
2726
DiagnosticCode::RustcHardError("E0559"),
2827
format!(
2928
"no field `{}` on type `{}`{method_suffix}",
3029
d.name.display(ctx.sema.db),
3130
d.receiver.display(ctx.sema.db)
3231
),
33-
d.expr.clone().map(|it| it.into()),
32+
adjusted_display_range_new(ctx, d.expr, &|expr| {
33+
Some(
34+
match expr {
35+
ast::Expr::MethodCallExpr(it) => it.name_ref(),
36+
ast::Expr::FieldExpr(it) => it.name_ref(),
37+
_ => None,
38+
}?
39+
.syntax()
40+
.text_range(),
41+
)
42+
}),
3443
)
3544
.with_fixes(fixes(ctx, d))
3645
.experimental()
@@ -79,7 +88,7 @@ mod tests {
7988
r#"
8089
fn main() {
8190
().foo;
82-
// ^^^^^^ error: no field `foo` on type `()`
91+
// ^^^ error: no field `foo` on type `()`
8392
}
8493
"#,
8594
);
@@ -95,7 +104,7 @@ impl Foo {
95104
}
96105
fn foo() {
97106
Foo.bar;
98-
// ^^^^^^^ 💡 error: no field `bar` on type `Foo`, but a method with a similar name exists
107+
// ^^^ 💡 error: no field `bar` on type `Foo`, but a method with a similar name exists
99108
}
100109
"#,
101110
);
@@ -112,7 +121,7 @@ trait Bar {
112121
impl Bar for Foo {}
113122
fn foo() {
114123
Foo.bar;
115-
// ^^^^^^^ 💡 error: no field `bar` on type `Foo`, but a method with a similar name exists
124+
// ^^^ 💡 error: no field `bar` on type `Foo`, but a method with a similar name exists
116125
}
117126
"#,
118127
);
@@ -131,7 +140,7 @@ impl Bar for Foo {
131140
}
132141
fn foo() {
133142
Foo.bar;
134-
// ^^^^^^^ 💡 error: no field `bar` on type `Foo`, but a method with a similar name exists
143+
// ^^^ 💡 error: no field `bar` on type `Foo`, but a method with a similar name exists
135144
}
136145
"#,
137146
);

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

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use ide_db::{
88
use syntax::{ast, AstNode, TextRange};
99
use text_edit::TextEdit;
1010

11-
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
11+
use crate::{adjusted_display_range_new, Diagnostic, DiagnosticCode, DiagnosticsContext};
1212

1313
// Diagnostic: unresolved-method
1414
//
@@ -22,15 +22,24 @@ pub(crate) fn unresolved_method(
2222
} else {
2323
""
2424
};
25-
Diagnostic::new_with_syntax_node_ptr(
26-
ctx,
25+
Diagnostic::new(
2726
DiagnosticCode::RustcHardError("E0599"),
2827
format!(
2928
"no method `{}` on type `{}`{field_suffix}",
3029
d.name.display(ctx.sema.db),
3130
d.receiver.display(ctx.sema.db)
3231
),
33-
d.expr.clone().map(|it| it.into()),
32+
adjusted_display_range_new(ctx, d.expr, &|expr| {
33+
Some(
34+
match expr {
35+
ast::Expr::MethodCallExpr(it) => it.name_ref(),
36+
ast::Expr::FieldExpr(it) => it.name_ref(),
37+
_ => None,
38+
}?
39+
.syntax()
40+
.text_range(),
41+
)
42+
}),
3443
)
3544
.with_fixes(fixes(ctx, d))
3645
.experimental()
@@ -92,7 +101,41 @@ mod tests {
92101
r#"
93102
fn main() {
94103
().foo();
95-
// ^^^^^^^^ error: no method `foo` on type `()`
104+
// ^^^ error: no method `foo` on type `()`
105+
}
106+
"#,
107+
);
108+
}
109+
110+
#[test]
111+
fn smoke_test_in_macro_def_site() {
112+
check_diagnostics(
113+
r#"
114+
macro_rules! m {
115+
($rcv:expr) => {
116+
$rcv.foo()
117+
}
118+
}
119+
fn main() {
120+
m!(());
121+
// ^^^^^^ error: no method `foo` on type `()`
122+
}
123+
"#,
124+
);
125+
}
126+
127+
#[test]
128+
fn smoke_test_in_macro_call_site() {
129+
check_diagnostics(
130+
r#"
131+
macro_rules! m {
132+
($ident:ident) => {
133+
().$ident()
134+
}
135+
}
136+
fn main() {
137+
m!(foo);
138+
// ^^^ error: no method `foo` on type `()`
96139
}
97140
"#,
98141
);
@@ -105,7 +148,7 @@ fn main() {
105148
struct Foo { bar: i32 }
106149
fn foo() {
107150
Foo { bar: i32 }.bar();
108-
// ^^^^^^^^^^^^^^^^^^^^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists
151+
// ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists
109152
}
110153
"#,
111154
);

crates/ide-diagnostics/src/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ use stdx::never;
9090
use syntax::{
9191
algo::find_node_at_range,
9292
ast::{self, AstNode},
93-
SyntaxNode, SyntaxNodePtr, TextRange,
93+
AstPtr, SyntaxNode, SyntaxNodePtr, TextRange,
9494
};
9595

9696
// FIXME: Make this an enum
@@ -584,3 +584,16 @@ fn adjusted_display_range<N: AstNode>(
584584
.unwrap_or(range),
585585
}
586586
}
587+
588+
// FIXME Replace the one above with this one?
589+
fn adjusted_display_range_new<N: AstNode>(
590+
ctx: &DiagnosticsContext<'_>,
591+
diag_ptr: InFile<AstPtr<N>>,
592+
adj: &dyn Fn(N) -> Option<TextRange>,
593+
) -> FileRange {
594+
let source_file = ctx.sema.parse_or_expand(diag_ptr.file_id);
595+
let node = diag_ptr.value.to_node(&source_file);
596+
diag_ptr
597+
.with_value(adj(node).unwrap_or_else(|| diag_ptr.value.text_range()))
598+
.original_node_file_range_rooted(ctx.sema.db)
599+
}

crates/syntax/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ doctest = false
1616
cov-mark = "2.0.0-pre.1"
1717
either.workspace = true
1818
itertools.workspace = true
19-
rowan = "0.15.11"
19+
rowan = "0.15.15"
2020
rustc-hash = "1.1.0"
2121
once_cell = "1.17.0"
2222
indexmap.workspace = true

crates/syntax/src/ptr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ impl<N: AstNode + std::fmt::Debug> std::fmt::Debug for AstPtr<N> {
3333
}
3434
}
3535

36+
impl<N: AstNode> Copy for AstPtr<N> {}
3637
impl<N: AstNode> Clone for AstPtr<N> {
3738
fn clone(&self) -> AstPtr<N> {
3839
AstPtr { raw: self.raw.clone(), _ty: PhantomData }

0 commit comments

Comments
 (0)