feat: lint ignored statements before break/continue/return (#1637)

* feat: impl it

* g

* g2

* feat: add tests

* fix: snapshot
This commit is contained in:
Myriad-Dreamin 2025-04-09 18:17:46 +08:00 committed by GitHub
parent 6cf7739fb6
commit 23f10a2648
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 1170 additions and 171 deletions

View file

@ -671,7 +671,7 @@ mod lint_tests {
let source = ctx.source_by_path(&path).unwrap();
let expr = ctx.expr_stage(&source);
let result = tinymist_lint::lint_source(&expr);
let result = tinymist_lint::lint_file(&expr);
let result = crate::diagnostics::DiagWorker::new(ctx).convert_all(result.iter());
let result = result
.into_iter()

View file

@ -247,5 +247,5 @@ impl DiagnosticRefiner for OutOfRootHintRefiner {
#[comemo::memoize]
fn lint_file(source: &ExprInfo) -> EcoVec<SourceDiagnostic> {
tinymist_lint::lint_source(source)
tinymist_lint::lint_file(source)
}

View file

@ -0,0 +1,3 @@
#for value in (1, 2, 3) {
break
}

View file

@ -0,0 +1,3 @@
#for value in (1, 2, 3) {
let _ = () => break
}

View file

@ -0,0 +1 @@
#break

View file

@ -0,0 +1,3 @@
#while true {
break
}

View file

@ -0,0 +1 @@
#continue

View file

@ -0,0 +1,4 @@
#let f() = [
#(1, 2)
#return 1;
]

View file

@ -0,0 +1,9 @@
#let f() = {
[0]
if true {
[1]
} else {
[2]
}
return [];
}

View file

@ -0,0 +1,7 @@
#let f() = {
while true {
[0]
break
}
return [];
}

View file

@ -0,0 +1,7 @@
#let f() = {
while true {
[0]
break
return [];
}
}

View file

@ -0,0 +1,4 @@
#let f() = [
$ 1 2 3 $
#return 1;
]

View file

@ -0,0 +1,4 @@
#let f() = for i in range(10) {
show: it => it
return [];
}

View file

@ -0,0 +1,4 @@
#let f() = for i in range(10) {
show: it => it
return ;
}

View file

@ -0,0 +1,3 @@
#let f() = for i in range(10) {
show: it => it
}

View file

@ -0,0 +1,4 @@
#let f() = for i in range(10) {
show: it => it
break
}

View file

@ -0,0 +1,4 @@
#let f() = for i in range(10) {
show: it => it
continue
}

View file

@ -0,0 +1,4 @@
#let f() = [
Hello -- Test -- World
#return 1;
]

View file

@ -0,0 +1,6 @@
#let f() = if true {
set text(red)
return;
} else {
return [];
}

View file

@ -0,0 +1,7 @@
#let f() = if true {
set text(red)
return;
} else {
set text(blue)
return [];
}

View file

@ -0,0 +1,8 @@
#let f() = {
if true {
[1]
} else {
[2]
}
return [];
}

View file

@ -0,0 +1,9 @@
#let f() = {
if true {
[1]
} else {
[2]
return;
}
return [];
}

View file

@ -0,0 +1,9 @@
#let f() = {
if true {
[1]
return;
} else {
[2]
}
return [];
}

View file

@ -0,0 +1,4 @@
#let f() = {
set text(red)
return 1;
}

View file

@ -0,0 +1,4 @@
#let f() = {
show: it => it
return 1;
}

View file

@ -0,0 +1,4 @@
#let f() = [
#show: it => it
#return 1;
]

View file

@ -1,4 +1,3 @@
#if false {
set text(red)
}

View file

@ -1,4 +1,3 @@
#if false {
show: text(red)
}

View file

@ -0,0 +1 @@
#context return

View file

@ -0,0 +1,3 @@
#while true {
return
}

View file

@ -0,0 +1,3 @@
#let f() = while true {
return
}

View file

@ -0,0 +1 @@
#let f() = return

View file

@ -0,0 +1 @@
#return

View file

@ -0,0 +1,4 @@
#let f() = {
show: it => it
[Test]
}

View file

@ -0,0 +1,4 @@
#let f() = [
#show: it => it
Test
]

View file

@ -1,4 +1,3 @@
#show: {
set text(red)
}

View file

@ -1,4 +1,3 @@
#show raw: {
set text(red)
}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/break_for.typ
---
{}

View file

@ -0,0 +1,23 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/break_func_for.typ
---
{
"s0.typ": [
{
"message": "`break` statement in a non-loop context",
"range": "1:16:1:21",
"relatedInformation": [
{
"message": "error occurred while applying show rule to this loop"
},
{
"message": "error occurred in this function call"
}
],
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/break_top.typ
---
{
"s0.typ": [
{
"message": "`break` statement in a non-loop context",
"range": "0:1:0:6",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/break_while.typ
---
{}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/continue_top.typ
---
{
"s0.typ": [
{
"message": "`continue` statement in a non-loop context",
"range": "0:1:0:9",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_array.typ
---
{
"s0.typ": [
{
"message": "This array is implicitly discarded by function return\nHint: consider ignoring the value explicitly using underscore: `let _ = (1, 2)`",
"range": "1:3:1:9",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,21 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_common.typ
---
{
"s0.typ": [
{
"message": "This text is implicitly discarded by function return",
"range": "3:5:3:6",
"severity": 2,
"source": "typst"
},
{
"message": "This text is implicitly discarded by function return",
"range": "5:5:5:6",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_common_break.typ
---
{}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_common_break2.typ
---
{}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_equation.typ
---
{
"s0.typ": [
{
"message": "This equation is implicitly discarded by function return",
"range": "1:2:1:11",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_for.typ
---
{
"s0.typ": [
{
"message": "This `show` expression is implicitly discarded by function return",
"range": "1:2:1:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_for2.typ
---
{
"s0.typ": [
{
"message": "This `show` expression is implicitly discarded by function return",
"range": "1:2:1:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_for3.typ
---
{
"s0.typ": [
{
"message": "This show statement doesn't take effect.\nHint: consider changing parent to `show: range(10).fold(it => it, (style-it, i) => it => { show: it => it; style-it(it) })`",
"range": "1:2:1:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_for4.typ
---
{
"s0.typ": [
{
"message": "This show statement doesn't take effect.\nHint: consider changing parent to `show: range(10).fold(it => it, (style-it, i) => it => { show: it => it; style-it(it) })`",
"range": "1:2:1:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_for5.typ
---
{
"s0.typ": [
{
"message": "This show statement doesn't take effect.\nHint: consider changing parent to `show: range(10).fold(it => it, (style-it, i) => it => { show: it => it; style-it(it) })`",
"range": "1:2:1:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_hello.typ
---
{
"s0.typ": [
{
"message": "This text is implicitly discarded by function return",
"range": "1:19:1:24",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_if.typ
---
{
"s0.typ": [
{
"message": "This `set` expression is implicitly discarded by function return",
"range": "1:2:1:15",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,21 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_if2.typ
---
{
"s0.typ": [
{
"message": "This `set` expression is implicitly discarded by function return",
"range": "1:2:1:15",
"severity": 2,
"source": "typst"
},
{
"message": "This `set` expression is implicitly discarded by function return",
"range": "4:2:4:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,21 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_join.typ
---
{
"s0.typ": [
{
"message": "This text is implicitly discarded by function return",
"range": "2:5:2:6",
"severity": 2,
"source": "typst"
},
{
"message": "This text is implicitly discarded by function return",
"range": "4:5:4:6",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_join_partial.typ
---
{
"s0.typ": [
{
"message": "This text is implicitly discarded by function return",
"range": "2:5:2:6",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_join_partial2.typ
---
{
"s0.typ": [
{
"message": "This text is implicitly discarded by function return",
"range": "5:5:5:6",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_set.typ
---
{
"s0.typ": [
{
"message": "This `set` expression is implicitly discarded by function return",
"range": "1:2:1:15",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_show.typ
---
{
"s0.typ": [
{
"message": "This `show` expression is implicitly discarded by function return",
"range": "1:2:1:16",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/discard_show_content.typ
---
{
"s0.typ": [
{
"message": "This `show` expression is implicitly discarded by function return",
"range": "1:3:1:17",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/return_contextual.typ
---
{}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/return_loop.typ
---
{
"s0.typ": [
{
"message": "`return` statement in a non-function context",
"range": "1:2:1:8",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/return_loop2.typ
---
{}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/return_regular.typ
---
{}

View file

@ -0,0 +1,15 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/return_top.typ
---
{
"s0.typ": [
{
"message": "`return` statement in a non-function context",
"range": "0:1:0:7",
"severity": 2,
"source": "typst"
}
]
}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/show_good.typ
---
{}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/show_good2.typ
---
{}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/while_good.typ
---
{}

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/analysis.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/lint/while_good2.typ
---
{}

View file

@ -0,0 +1,6 @@
#let f() = {
while true {
[0]
break
}
}

View file

@ -0,0 +1,5 @@
#let f() = {
while false {
[0]
}
}