mirror of
https://github.com/oxalica/nil.git
synced 2024-11-30 01:54:53 +03:00
Tweak Diagnostic usage
This commit is contained in:
parent
904ac9d9ec
commit
746ebad9fc
113
src/def/lower.rs
113
src/def/lower.rs
@ -10,7 +10,7 @@ use rowan::ast::AstNode;
|
|||||||
use smol_str::SmolStr;
|
use smol_str::SmolStr;
|
||||||
use std::{mem, str};
|
use std::{mem, str};
|
||||||
use syntax::ast::{self, HasBindings, HasStringParts, LiteralKind};
|
use syntax::ast::{self, HasBindings, HasStringParts, LiteralKind};
|
||||||
use syntax::{Parse, TextRange};
|
use syntax::Parse;
|
||||||
|
|
||||||
pub(super) fn lower(
|
pub(super) fn lower(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
@ -63,8 +63,8 @@ impl LowerCtx<'_> {
|
|||||||
self.module.bindings.alloc(Binding { key, value })
|
self.module.bindings.alloc(Binding { key, value })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostic(&mut self, range: TextRange, kind: DiagnosticKind) {
|
fn diagnostic(&mut self, diag: Diagnostic) {
|
||||||
self.module.diagnostics.push(Diagnostic { range, kind });
|
self.module.diagnostics.push(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_name(&mut self, node: ast::Name, kind: NameDefKind) -> NameDefId {
|
fn lower_name(&mut self, node: ast::Name, kind: NameDefKind) -> NameDefId {
|
||||||
@ -179,7 +179,7 @@ impl LowerCtx<'_> {
|
|||||||
let let_in_header = e
|
let let_in_header = e
|
||||||
.in_token()
|
.in_token()
|
||||||
.map_or(let_tok_range, |tok| tok.text_range().cover(let_tok_range));
|
.map_or(let_tok_range, |tok| tok.text_range().cover(let_tok_range));
|
||||||
self.diagnostic(let_in_header, DiagnosticKind::EmptyLetIn);
|
self.diagnostic(Diagnostic::new(let_in_header, DiagnosticKind::EmptyLetIn));
|
||||||
}
|
}
|
||||||
let body = self.lower_expr_opt(e.body());
|
let body = self.lower_expr_opt(e.body());
|
||||||
self.alloc_expr(Expr::LetIn(bindings, body), ptr)
|
self.alloc_expr(Expr::LetIn(bindings, body), ptr)
|
||||||
@ -189,7 +189,10 @@ impl LowerCtx<'_> {
|
|||||||
let (def_kind, ctor): (_, fn(_) -> _) = if e.rec_token().is_some() {
|
let (def_kind, ctor): (_, fn(_) -> _) = if e.rec_token().is_some() {
|
||||||
(Some(NameDefKind::RecAttrset), Expr::RecAttrset)
|
(Some(NameDefKind::RecAttrset), Expr::RecAttrset)
|
||||||
} else if e.let_token().is_some() {
|
} else if e.let_token().is_some() {
|
||||||
self.diagnostic(e.syntax().text_range(), DiagnosticKind::LetAttrset);
|
self.diagnostic(Diagnostic::new(
|
||||||
|
e.syntax().text_range(),
|
||||||
|
DiagnosticKind::LetAttrset,
|
||||||
|
));
|
||||||
(Some(NameDefKind::RecAttrset), Expr::LetAttrset)
|
(Some(NameDefKind::RecAttrset), Expr::LetAttrset)
|
||||||
} else {
|
} else {
|
||||||
(None, Expr::Attrset)
|
(None, Expr::Attrset)
|
||||||
@ -221,7 +224,10 @@ impl LowerCtx<'_> {
|
|||||||
LiteralKind::Int => Literal::Int(text.parse::<i64>().ok()?),
|
LiteralKind::Int => Literal::Int(text.parse::<i64>().ok()?),
|
||||||
LiteralKind::Float => Literal::Float(text.parse::<f64>().unwrap().into()),
|
LiteralKind::Float => Literal::Float(text.parse::<f64>().unwrap().into()),
|
||||||
LiteralKind::Uri => {
|
LiteralKind::Uri => {
|
||||||
self.diagnostic(lit.syntax().text_range(), DiagnosticKind::UriLiteral);
|
self.diagnostic(Diagnostic::new(
|
||||||
|
lit.syntax().text_range(),
|
||||||
|
DiagnosticKind::UriLiteral,
|
||||||
|
));
|
||||||
Literal::String(text.into())
|
Literal::String(text.into())
|
||||||
}
|
}
|
||||||
LiteralKind::SearchPath => {
|
LiteralKind::SearchPath => {
|
||||||
@ -416,7 +422,10 @@ impl MergingSet {
|
|||||||
let key = match ctx.lower_key(attr, self.def_kind) {
|
let key = match ctx.lower_key(attr, self.def_kind) {
|
||||||
// `inherit ${expr}` or `inherit (expr) ${expr}` is invalid.
|
// `inherit ${expr}` or `inherit (expr) ${expr}` is invalid.
|
||||||
BindingKey::Dynamic(expr) => {
|
BindingKey::Dynamic(expr) => {
|
||||||
ctx.diagnostic(ptr.text_range(), DiagnosticKind::InvalidDynamic);
|
ctx.diagnostic(Diagnostic::new(
|
||||||
|
ptr.text_range(),
|
||||||
|
DiagnosticKind::InvalidDynamic,
|
||||||
|
));
|
||||||
self.recover_error(ctx, expr, ptr.clone());
|
self.recover_error(ctx, expr, ptr.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -450,7 +459,10 @@ impl MergingSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if no_attrs {
|
if no_attrs {
|
||||||
ctx.diagnostic(i.syntax().text_range(), DiagnosticKind::EmptyInherit);
|
ctx.diagnostic(Diagnostic::new(
|
||||||
|
i.syntax().text_range(),
|
||||||
|
DiagnosticKind::EmptyInherit,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +485,10 @@ impl MergingSet {
|
|||||||
|
|
||||||
// LetIn doesn't allow dynamic attrs.
|
// LetIn doesn't allow dynamic attrs.
|
||||||
if let (Some(NameDefKind::LetIn), BindingKey::Dynamic(_)) = (self.def_kind, &key) {
|
if let (Some(NameDefKind::LetIn), BindingKey::Dynamic(_)) = (self.def_kind, &key) {
|
||||||
ctx.diagnostic(attr_ptr.text_range(), DiagnosticKind::InvalidDynamic);
|
ctx.diagnostic(Diagnostic::new(
|
||||||
|
attr_ptr.text_range(),
|
||||||
|
DiagnosticKind::InvalidDynamic,
|
||||||
|
));
|
||||||
// We don't skip the RHS but still process it as a recovery.
|
// We don't skip the RHS but still process it as a recovery.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,9 +541,15 @@ impl MergingEntry {
|
|||||||
let prev_is_rec = prev_set.def_kind.is_some();
|
let prev_is_rec = prev_set.def_kind.is_some();
|
||||||
let this_is_rec = def_kind.is_some();
|
let this_is_rec = def_kind.is_some();
|
||||||
if prev_is_rec {
|
if prev_is_rec {
|
||||||
ctx.diagnostic(def_ptr.text_range(), DiagnosticKind::MergeRecAttrset);
|
ctx.diagnostic(Diagnostic::new(
|
||||||
|
def_ptr.text_range(),
|
||||||
|
DiagnosticKind::MergeRecAttrset,
|
||||||
|
));
|
||||||
} else if this_is_rec {
|
} else if this_is_rec {
|
||||||
ctx.diagnostic(def_ptr.text_range(), DiagnosticKind::MergePlainRecAttrset);
|
ctx.diagnostic(Diagnostic::new(
|
||||||
|
def_ptr.text_range(),
|
||||||
|
DiagnosticKind::MergePlainRecAttrset,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We prefer to become a Attrset as a guess, which allows further merging.
|
// We prefer to become a Attrset as a guess, which allows further merging.
|
||||||
@ -583,11 +604,17 @@ impl MergingEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emit_duplicated_key(&mut self, ctx: &mut LowerCtx, ptr: &AstPtr) {
|
fn emit_duplicated_key(&mut self, ctx: &mut LowerCtx, ptr: &AstPtr) {
|
||||||
|
// Don't emit twice at the previous key.
|
||||||
if !mem::replace(&mut self.is_duplicated, true) {
|
if !mem::replace(&mut self.is_duplicated, true) {
|
||||||
// Don't emit twice at previouse key.
|
ctx.diagnostic(Diagnostic::new(
|
||||||
ctx.diagnostic(self.def_ptr.text_range(), DiagnosticKind::DuplicatedKey);
|
self.def_ptr.text_range(),
|
||||||
|
DiagnosticKind::DuplicatedKey,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
ctx.diagnostic(ptr.text_range(), DiagnosticKind::DuplicatedKey);
|
ctx.diagnostic(Diagnostic::new(
|
||||||
|
ptr.text_range(),
|
||||||
|
DiagnosticKind::DuplicatedKey,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self, ctx: &mut LowerCtx) -> BindingValue {
|
fn finish(self, ctx: &mut LowerCtx) -> BindingValue {
|
||||||
@ -624,7 +651,7 @@ mod tests {
|
|||||||
let module = db.module(file_id);
|
let module = db.module(file_id);
|
||||||
let mut got = String::new();
|
let mut got = String::new();
|
||||||
for diag in module.diagnostics() {
|
for diag in module.diagnostics() {
|
||||||
writeln!(got, "{:?}", diag).unwrap();
|
writeln!(got, "{}", diag.debug_to_string()).unwrap();
|
||||||
}
|
}
|
||||||
if !module.diagnostics.is_empty() {
|
if !module.diagnostics.is_empty() {
|
||||||
writeln!(got).unwrap();
|
writeln!(got).unwrap();
|
||||||
@ -664,7 +691,7 @@ mod tests {
|
|||||||
let module = db.module(file_id);
|
let module = db.module(file_id);
|
||||||
let mut got = String::new();
|
let mut got = String::new();
|
||||||
for diag in module.diagnostics() {
|
for diag in module.diagnostics() {
|
||||||
writeln!(got, "{:?}", diag).unwrap();
|
writeln!(got, "{}", diag.debug_to_string()).unwrap();
|
||||||
}
|
}
|
||||||
expect.assert_eq(&got);
|
expect.assert_eq(&got);
|
||||||
}
|
}
|
||||||
@ -686,7 +713,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"a:b",
|
"a:b",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 0..3, kind: UriLiteral }
|
0..3: URL literal is confusing and deprecated. Use strings instead
|
||||||
|
|
||||||
0: Literal(String("a:b"))
|
0: Literal(String("a:b"))
|
||||||
"#]],
|
"#]],
|
||||||
@ -882,7 +909,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"foo:bar",
|
"foo:bar",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 0..7, kind: UriLiteral }
|
0..7: URL literal is confusing and deprecated. Use strings instead
|
||||||
|
|
||||||
0: Literal(String("foo:bar"))
|
0: Literal(String("foo:bar"))
|
||||||
"#]],
|
"#]],
|
||||||
@ -939,8 +966,8 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
r#"{ inherit; inherit a "b" ${("c")}; inherit (d); inherit (e) f g; }"#,
|
r#"{ inherit; inherit a "b" ${("c")}; inherit (d); inherit (e) f g; }"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 2..10, kind: EmptyInherit }
|
2..10: Nothing inherited
|
||||||
Diagnostic { range: 35..47, kind: EmptyInherit }
|
35..47: Nothing inherited
|
||||||
|
|
||||||
0: Reference("a")
|
0: Reference("a")
|
||||||
1: Reference("b")
|
1: Reference("b")
|
||||||
@ -1024,7 +1051,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"{ a = rec { b = 1; }; a = { c = 2; }; }",
|
"{ a = rec { b = 1; }; a = { c = 2; }; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 26..36, kind: MergeRecAttrset }
|
26..36: Merging rec-attrset with other attrsets or attrpath. Merged values can unexpectedly reference each other remotely as in a single `rec { ... }`
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: Literal(Int(2))
|
1: Literal(Int(2))
|
||||||
@ -1044,7 +1071,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"{ a = rec { b = 1; }; a.c = 2; }",
|
"{ a = rec { b = 1; }; a.c = 2; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 22..23, kind: MergeRecAttrset }
|
22..23: Merging rec-attrset with other attrsets or attrpath. Merged values can unexpectedly reference each other remotely as in a single `rec { ... }`
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: Literal(Int(2))
|
1: Literal(Int(2))
|
||||||
@ -1064,7 +1091,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"{ a = { b = 1; }; a = rec { c = 2; }; }",
|
"{ a = { b = 1; }; a = rec { c = 2; }; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 22..36, kind: MergePlainRecAttrset }
|
22..36: Merging non-rec-attrset with rec-attrset, the latter `rec` is implicitly ignored
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: Literal(Int(2))
|
1: Literal(Int(2))
|
||||||
@ -1081,7 +1108,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"{ a.b = 1; a = rec { c = 2; }; }",
|
"{ a.b = 1; a = rec { c = 2; }; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 15..29, kind: MergePlainRecAttrset }
|
15..29: Merging non-rec-attrset with rec-attrset, the latter `rec` is implicitly ignored
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: Literal(Int(2))
|
1: Literal(Int(2))
|
||||||
@ -1098,7 +1125,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"{ a = rec { b = 1; }; a = rec { c = 2; }; }",
|
"{ a = rec { b = 1; }; a = rec { c = 2; }; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 26..40, kind: MergeRecAttrset }
|
26..40: Merging rec-attrset with other attrsets or attrpath. Merged values can unexpectedly reference each other remotely as in a single `rec { ... }`
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: Literal(Int(2))
|
1: Literal(Int(2))
|
||||||
@ -1157,7 +1184,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"{ a.b = let { c.d = 1; }; }",
|
"{ a.b = let { c.d = 1; }; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 8..24, kind: LetAttrset }
|
8..24: `let { ... }` is deprecated. Use `let ... in ...` instead
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: Attrset(Bindings { entries: [Idx::<Binding>(0)], inherit_froms: [] })
|
1: Attrset(Bindings { entries: [Idx::<Binding>(0)], inherit_froms: [] })
|
||||||
@ -1201,7 +1228,7 @@ mod tests {
|
|||||||
check_lower(
|
check_lower(
|
||||||
"let in 1",
|
"let in 1",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 0..6, kind: EmptyLetIn }
|
0..6: Empty let-in
|
||||||
|
|
||||||
0: Literal(Int(1))
|
0: Literal(Int(1))
|
||||||
1: LetIn(Bindings { entries: [], inherit_froms: [] }, Idx::<Expr>(0))
|
1: LetIn(Bindings { entries: [], inherit_froms: [] }, Idx::<Expr>(0))
|
||||||
@ -1233,19 +1260,19 @@ mod tests {
|
|||||||
check_error(
|
check_error(
|
||||||
"let ${a} = 1; in 1",
|
"let ${a} = 1; in 1",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 4..8, kind: InvalidDynamic }
|
4..8: Invalid location of dynamic attribute
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_error(
|
check_error(
|
||||||
"{ inherit ${a}; }",
|
"{ inherit ${a}; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 10..14, kind: InvalidDynamic }
|
10..14: Invalid location of dynamic attribute
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_error(
|
check_error(
|
||||||
"{ inherit (a) ${a}; }",
|
"{ inherit (a) ${a}; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 14..18, kind: InvalidDynamic }
|
14..18: Invalid location of dynamic attribute
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1256,40 +1283,40 @@ mod tests {
|
|||||||
check_error(
|
check_error(
|
||||||
"{ a = 1; a = 2; }",
|
"{ a = 1; a = 2; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 2..3, kind: DuplicatedKey }
|
2..3: Duplicated name definition
|
||||||
Diagnostic { range: 9..10, kind: DuplicatedKey }
|
9..10: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
// Set and value.
|
// Set and value.
|
||||||
check_error(
|
check_error(
|
||||||
"{ a.b = 1; a = 2; }",
|
"{ a.b = 1; a = 2; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 2..3, kind: DuplicatedKey }
|
2..3: Duplicated name definition
|
||||||
Diagnostic { range: 11..12, kind: DuplicatedKey }
|
11..12: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
// Value and set.
|
// Value and set.
|
||||||
check_error(
|
check_error(
|
||||||
"{ a = 1; a.b = 2; }",
|
"{ a = 1; a.b = 2; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 2..3, kind: DuplicatedKey }
|
2..3: Duplicated name definition
|
||||||
Diagnostic { range: 9..10, kind: DuplicatedKey }
|
9..10: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
// Inherit and value.
|
// Inherit and value.
|
||||||
check_error(
|
check_error(
|
||||||
"{ inherit a; a = 1; }",
|
"{ inherit a; a = 1; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 10..11, kind: DuplicatedKey }
|
10..11: Duplicated name definition
|
||||||
Diagnostic { range: 13..14, kind: DuplicatedKey }
|
13..14: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
// Inherit-from and value.
|
// Inherit-from and value.
|
||||||
check_error(
|
check_error(
|
||||||
"{ inherit (1) a; a = 1; }",
|
"{ inherit (1) a; a = 1; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 14..15, kind: DuplicatedKey }
|
14..15: Duplicated name definition
|
||||||
Diagnostic { range: 17..18, kind: DuplicatedKey }
|
17..18: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1299,9 +1326,9 @@ mod tests {
|
|||||||
check_error(
|
check_error(
|
||||||
"{ a = 1; a = 2; a = 3; }",
|
"{ a = 1; a = 2; a = 3; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Diagnostic { range: 2..3, kind: DuplicatedKey }
|
2..3: Duplicated name definition
|
||||||
Diagnostic { range: 9..10, kind: DuplicatedKey }
|
9..10: Duplicated name definition
|
||||||
Diagnostic { range: 16..17, kind: DuplicatedKey }
|
16..17: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::fmt;
|
|
||||||
use syntax::{ErrorKind as SynErrorKind, TextRange};
|
use syntax::{ErrorKind as SynErrorKind, TextRange};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Diagnostic {
|
pub struct Diagnostic {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub kind: DiagnosticKind,
|
pub kind: DiagnosticKind,
|
||||||
@ -36,6 +35,10 @@ pub enum Severity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Diagnostic {
|
impl Diagnostic {
|
||||||
|
pub fn new(range: TextRange, kind: DiagnosticKind) -> Self {
|
||||||
|
Self { range, kind }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn severity(&self) -> Severity {
|
pub fn severity(&self) -> Severity {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
DiagnosticKind::InvalidDynamic | DiagnosticKind::DuplicatedKey => Severity::Error,
|
DiagnosticKind::InvalidDynamic | DiagnosticKind::DuplicatedKey => Severity::Error,
|
||||||
@ -79,7 +82,7 @@ impl Diagnostic {
|
|||||||
"Merging non-rec-attrset with rec-attrset, the latter `rec` is implicitly ignored"
|
"Merging non-rec-attrset with rec-attrset, the latter `rec` is implicitly ignored"
|
||||||
}
|
}
|
||||||
DiagnosticKind::MergeRecAttrset => {
|
DiagnosticKind::MergeRecAttrset => {
|
||||||
"Merging rec-attrset with other attrsets or attrpath. Merged values can unexpectedly reference each other remotely as in a single `rec { ... }`."
|
"Merging rec-attrset with other attrsets or attrpath. Merged values can unexpectedly reference each other remotely as in a single `rec { ... }`"
|
||||||
}
|
}
|
||||||
|
|
||||||
DiagnosticKind::UnusedBinding => "Unused binding",
|
DiagnosticKind::UnusedBinding => "Unused binding",
|
||||||
@ -105,25 +108,19 @@ impl Diagnostic {
|
|||||||
DiagnosticKind::LetAttrset | DiagnosticKind::UriLiteral
|
DiagnosticKind::LetAttrset | DiagnosticKind::UriLiteral
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn debug_to_string(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"{}..{}: {}",
|
||||||
|
u32::from(self.range.start()),
|
||||||
|
u32::from(self.range.end()),
|
||||||
|
self.message(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<syntax::Error> for Diagnostic {
|
impl From<syntax::Error> for Diagnostic {
|
||||||
fn from(err: syntax::Error) -> Self {
|
fn from(err: syntax::Error) -> Self {
|
||||||
Self {
|
Self::new(err.range, DiagnosticKind::SyntaxError(err.kind))
|
||||||
range: err.range,
|
|
||||||
kind: DiagnosticKind::SyntaxError(err.kind),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Diagnostic {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{} at {}..{}",
|
|
||||||
self.message(),
|
|
||||||
u32::from(self.range.start()),
|
|
||||||
u32::from(self.range.end()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,36 +17,32 @@ pub(crate) fn diagnostics(db: &dyn DefDatabase, file: FileId) -> Vec<Diagnostic>
|
|||||||
// Liveness check.
|
// Liveness check.
|
||||||
let liveness = db.liveness_check(file);
|
let liveness = db.liveness_check(file);
|
||||||
let source_map = db.source_map(file);
|
let source_map = db.source_map(file);
|
||||||
diags.extend(liveness.unused_name_defs().iter().map(|&def| Diagnostic {
|
diags.extend(liveness.unused_name_defs().iter().map(|&def| {
|
||||||
range: source_map.name_def_node(def).unwrap().text_range(),
|
Diagnostic::new(
|
||||||
kind: DiagnosticKind::UnusedBinding,
|
source_map.name_def_node(def).unwrap().text_range(),
|
||||||
|
DiagnosticKind::UnusedBinding,
|
||||||
|
)
|
||||||
}));
|
}));
|
||||||
diags.extend(liveness.unused_withs().iter().map(|&expr| {
|
diags.extend(liveness.unused_withs().iter().filter_map(|&expr| {
|
||||||
let ptr = source_map.expr_node(expr).expect("Must be With");
|
let ptr = source_map.expr_node(expr)?;
|
||||||
let node = ast::With::cast(ptr.to_node(&parse.syntax_node())).expect("Must be With");
|
let node = ast::With::cast(ptr.to_node(&parse.syntax_node()))?;
|
||||||
let with_token_range = node
|
let with_token_range = node.with_token()?.text_range();
|
||||||
.with_token()
|
|
||||||
.expect("With must has `with` token")
|
|
||||||
.text_range();
|
|
||||||
let with_header_range = node.semicolon_token().map_or_else(
|
let with_header_range = node.semicolon_token().map_or_else(
|
||||||
|| node.syntax().text_range(),
|
|| node.syntax().text_range(),
|
||||||
|tok| tok.text_range().cover(with_token_range),
|
|tok| tok.text_range().cover(with_token_range),
|
||||||
);
|
);
|
||||||
Diagnostic {
|
Some(Diagnostic::new(
|
||||||
range: with_header_range,
|
with_header_range,
|
||||||
kind: DiagnosticKind::UnusedWith,
|
DiagnosticKind::UnusedWith,
|
||||||
}
|
))
|
||||||
}));
|
}));
|
||||||
diags.extend(liveness.unused_recs().iter().map(|&expr| {
|
diags.extend(liveness.unused_recs().iter().filter_map(|&expr| {
|
||||||
let ptr = source_map.expr_node(expr).expect("Must be Attrset");
|
let ptr = source_map.expr_node(expr)?;
|
||||||
let node = ast::AttrSet::cast(ptr.to_node(&parse.syntax_node())).expect("Must be Attrset");
|
let node = ast::AttrSet::cast(ptr.to_node(&parse.syntax_node()))?;
|
||||||
let rec_range = node
|
let rec_range = node
|
||||||
.rec_token()
|
.rec_token()
|
||||||
.map_or_else(|| node.syntax().text_range(), |tok| tok.text_range());
|
.map_or_else(|| node.syntax().text_range(), |tok| tok.text_range());
|
||||||
Diagnostic {
|
Some(Diagnostic::new(rec_range, DiagnosticKind::UnusedRec))
|
||||||
range: rec_range,
|
|
||||||
kind: DiagnosticKind::UnusedRec,
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
diags
|
diags
|
||||||
@ -63,7 +59,7 @@ mod tests {
|
|||||||
assert!(!diags.is_empty());
|
assert!(!diags.is_empty());
|
||||||
let got = diags
|
let got = diags
|
||||||
.iter()
|
.iter()
|
||||||
.map(|d| d.to_string() + "\n")
|
.map(|d| d.debug_to_string() + "\n")
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("");
|
.join("");
|
||||||
expect.assert_eq(&got);
|
expect.assert_eq(&got);
|
||||||
@ -74,7 +70,7 @@ mod tests {
|
|||||||
check(
|
check(
|
||||||
"1 == 2 == 3",
|
"1 == 2 == 3",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Invalid usage of no-associative operators at 7..9
|
7..9: Invalid usage of no-associative operators
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -84,8 +80,8 @@ mod tests {
|
|||||||
check(
|
check(
|
||||||
"{ a = 1; a = 2; }",
|
"{ a = 1; a = 2; }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Duplicated name definition at 2..3
|
2..3: Duplicated name definition
|
||||||
Duplicated name definition at 9..10
|
9..10: Duplicated name definition
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -95,9 +91,9 @@ mod tests {
|
|||||||
check(
|
check(
|
||||||
"let a = a; b = 1; in with 1; b + rec { }",
|
"let a = a; b = 1; in with 1; b + rec { }",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Unused binding at 4..5
|
4..5: Unused binding
|
||||||
Unused `with` at 21..28
|
21..28: Unused `with`
|
||||||
Unused `rec` at 33..36
|
33..36: Unused `rec`
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user