diff --git a/crates/ruff/tests/cli/snapshots/cli__lint__output_format_github.snap b/crates/ruff/tests/cli/snapshots/cli__lint__output_format_github.snap index 32dc44924810e..631519ad56e09 100644 --- a/crates/ruff/tests/cli/snapshots/cli__lint__output_format_github.snap +++ b/crates/ruff/tests/cli/snapshots/cli__lint__output_format_github.snap @@ -16,7 +16,7 @@ info: success: false exit_code: 1 ----- stdout ----- -::error title=ruff (F401),file=[TMP]/input.py,line=1,col=8,endLine=1,endColumn=10::input.py:1:8: F401 `os` imported but unused +::error title=ruff (F401),file=[TMP]/input.py,line=1,col=8,endLine=1,endColumn=10::input.py:1:8: F401 `os` imported but unused%0A help: Remove unused import: `os` ::error title=ruff (F821),file=[TMP]/input.py,line=2,col=5,endLine=2,endColumn=6::input.py:2:5: F821 Undefined name `y` ::error title=ruff (invalid-syntax),file=[TMP]/input.py,line=3,col=1,endLine=3,endColumn=6::input.py:3:1: invalid-syntax: Cannot use `match` statement on Python 3.9 (syntax was added in Python 3.10) diff --git a/crates/ruff_db/src/diagnostic/mod.rs b/crates/ruff_db/src/diagnostic/mod.rs index 70cf38e8ea47c..6f14e1aebb324 100644 --- a/crates/ruff_db/src/diagnostic/mod.rs +++ b/crates/ruff_db/src/diagnostic/mod.rs @@ -317,17 +317,7 @@ impl Diagnostic { /// Returns all annotations, skipping the first primary annotation. pub fn secondary_annotations(&self) -> impl Iterator { - let mut seen_primary = false; - self.inner.annotations.iter().filter(move |ann| { - if seen_primary { - true - } else if ann.is_primary { - seen_primary = true; - false - } else { - true - } - }) + secondary_annotations(self.inner.annotations.iter()) } pub fn sub_diagnostics(&self) -> &[SubDiagnostic] { @@ -669,6 +659,11 @@ impl SubDiagnostic { &self.inner.annotations } + /// Returns all annotations, skipping the first primary annotation. + pub fn secondary_annotations(&self) -> impl Iterator { + secondary_annotations(self.inner.annotations.iter()) + } + /// Returns a mutable borrow of the annotations of this sub-diagnostic. pub fn annotations_mut(&mut self) -> impl Iterator { self.inner.annotations.iter_mut() @@ -707,6 +702,10 @@ impl SubDiagnostic { ConciseMessage::Both { main, annotation } } } + + pub(crate) fn severity(&self) -> SubDiagnosticSeverity { + self.inner.severity + } } #[derive(Debug, Clone, Eq, PartialEq, Hash, get_size2::GetSize)] @@ -716,6 +715,23 @@ struct SubDiagnosticInner { annotations: Vec, } +/// Returns all annotations, skipping the first primary annotation. +fn secondary_annotations<'a>( + annotations: impl Iterator, +) -> impl Iterator { + let mut seen_primary = false; + annotations.filter(move |ann| { + if seen_primary { + true + } else if ann.is_primary { + seen_primary = true; + false + } else { + true + } + }) +} + /// A pointer to a subsequence in the end user's input. /// /// Also known as an annotation, the pointer can optionally contain a short diff --git a/crates/ruff_db/src/diagnostic/render.rs b/crates/ruff_db/src/diagnostic/render.rs index 1770ebcacfaea..e41763e466b7a 100644 --- a/crates/ruff_db/src/diagnostic/render.rs +++ b/crates/ruff_db/src/diagnostic/render.rs @@ -2798,6 +2798,16 @@ watermelon self } + /// Adds a sub-diagnostic constructed with this diagnostic's environment. + fn sub( + mut self, + f: impl Fn(&mut TestEnvironment) -> SubDiagnostic, + ) -> DiagnosticBuilder<'e> { + let sub = f(self.env); + self.diag.sub(sub); + self + } + /// Set the documentation URL for the diagnostic. pub(super) fn documentation_url(mut self, url: impl Into) -> DiagnosticBuilder<'e> { self.diag.set_documentation_url(Some(url.into())); @@ -2901,7 +2911,7 @@ def fibonacci(n): elif n == 1: return 1 else: - return fibonacci(n - 1) + fibonacci(n - 2) + return fibonaccii(n - 1) + fibonacci(n - 2) "#, ); env.add("undef.py", r"if a == 1: pass"); @@ -2940,6 +2950,26 @@ def fibonacci(n): .noqa_offset(TextSize::from(3)) .documentation_url("https://docs.astral.sh/ruff/rules/undefined-name") .build(), + env.builder( + "undefined-name", + Severity::Error, + "Undefined name `fibonaccii`", + ) + .primary("fib.py", "12:15", "12:25", "") + .secondary_code("F821") + .noqa_offset(ruff_text_size::TextSize::from(0)) + .documentation_url("https://docs.astral.sh/ruff/rules/undefined-name") + .secondary("fib.py", "12:35", "12:36", "") + .sub(|env| { + env.sub_builder( + SubDiagnosticSeverity::Info, + "Did you mean to import it from `/some/path/def.py`?", + ) + .primary("fib.py", "4:4", "4:13", "`fibonacci` is defined here") + .secondary("fib.py", "5:4", "5", "`fibonacci` is documented here") + .build() + }) + .build(), ]; (env, diagnostics) @@ -2973,36 +3003,6 @@ if call(foo (env, diagnostics) } - /// Create Ruff-style diagnostics with sub-diagnostics for testing the various output formats. - pub(crate) fn create_sub_diagnostics( - format: DiagnosticFormat, - ) -> (TestEnvironment, Vec) { - let mut env = TestEnvironment::new(); - env.add("/some/path/def.py", "def f(): pass"); - env.add("call.py", "f()"); - env.format(format); - - let mut primary_diagnostic = env - .builder("undefined-name", Severity::Error, "Undefined name `f`") - .primary("call.py", "1:0", "1:1", "") - .secondary_code("F821") - .noqa_offset(ruff_text_size::TextSize::from(0)) - .documentation_url("https://docs.astral.sh/ruff/rules/undefined-name") - .build(); - - let sub_diagnostic = env - .sub_builder( - SubDiagnosticSeverity::Info, - "Did you mean to import it from `/some/path/def.py`?", - ) - .primary("/some/path/def.py", "1:4", "1:5", "`f` is defined here") - .build(); - - primary_diagnostic.sub(sub_diagnostic); - - (env, vec![primary_diagnostic]) - } - /// A Jupyter notebook for testing diagnostics. /// /// diff --git a/crates/ruff_db/src/diagnostic/render/concise.rs b/crates/ruff_db/src/diagnostic/render/concise.rs index ea8e8bfaceaf3..97ae8e0ec1084 100644 --- a/crates/ruff_db/src/diagnostic/render/concise.rs +++ b/crates/ruff_db/src/diagnostic/render/concise.rs @@ -141,6 +141,7 @@ mod tests { fib.py:1:8: error[unused-import] `os` imported but unused fib.py:6:5: error[unused-variable] Local variable `x` is assigned to but never used undef.py:1:4: error[undefined-name] Undefined name `a` + fib.py:12:16: error[undefined-name] Undefined name `fibonaccii` "); } @@ -154,6 +155,7 @@ mod tests { fib.py:1:8: F401 [*] `os` imported but unused fib.py:6:5: F841 [*] Local variable `x` is assigned to but never used undef.py:1:4: F821 Undefined name `a` + fib.py:12:16: F821 Undefined name `fibonaccii` "); } @@ -168,6 +170,7 @@ mod tests { fib.py:1:8: F401 [*] `os` imported but unused fib.py:6:5: F841 [*] Local variable `x` is assigned to but never used undef.py:1:4: F821 Undefined name `a` + fib.py:12:16: F821 Undefined name `fibonaccii` "); } diff --git a/crates/ruff_db/src/diagnostic/render/full.rs b/crates/ruff_db/src/diagnostic/render/full.rs index 986077fac17ec..ebe2de20a24fb 100644 --- a/crates/ruff_db/src/diagnostic/render/full.rs +++ b/crates/ruff_db/src/diagnostic/render/full.rs @@ -338,6 +338,25 @@ mod tests { 1 | if a == 1: pass | ^ | + + error[undefined-name]: Undefined name `fibonaccii` + --> fib.py:12:16 + | + 10 | return 1 + 11 | else: + 12 | return fibonaccii(n - 1) + fibonacci(n - 2) + | ^^^^^^^^^^ - + | + info: Did you mean to import it from `/some/path/def.py`? + --> fib.py:4:5 + | + 4 | def fibonacci(n): + | ^^^^^^^^^ `fibonacci` is defined here + 5 | """Compute the nth number in the Fibonacci sequence.""" + | ------------------------------------------------------- `fibonacci` is documented here + 6 | x = 1 + 7 | if n == 0: + | "#); } @@ -401,6 +420,25 @@ mod tests { 1 | if a == 1: pass | ^ | + + F821 Undefined name `fibonaccii` + --> fib.py:12:16 + | + 10 | return 1 + 11 | else: + 12 | return fibonaccii(n - 1) + fibonacci(n - 2) + | ^^^^^^^^^^ - + | + info: Did you mean to import it from `/some/path/def.py`? + --> fib.py:4:5 + | + 4 | def fibonacci(n): + | ^^^^^^^^^ `fibonacci` is defined here + 5 | """Compute the nth number in the Fibonacci sequence.""" + | ------------------------------------------------------- `fibonacci` is documented here + 6 | x = 1 + 7 | if n == 0: + | "#); } diff --git a/crates/ruff_db/src/diagnostic/render/github.rs b/crates/ruff_db/src/diagnostic/render/github.rs index dc4d492be331c..bba48c2ec83d5 100644 --- a/crates/ruff_db/src/diagnostic/render/github.rs +++ b/crates/ruff_db/src/diagnostic/render/github.rs @@ -1,4 +1,8 @@ -use crate::diagnostic::{Diagnostic, FileResolver, Severity}; +use ruff_text_size::TextRange; + +use crate::diagnostic::{ + Annotation, Diagnostic, FileResolver, Severity, SubDiagnosticSeverity, UnifiedFile, +}; pub(super) struct GithubRenderer<'a> { resolver: &'a dyn FileResolver, @@ -87,13 +91,97 @@ impl<'a> GithubRenderer<'a> { write!(f, "{id}:", id = diagnostic.id())?; } - writeln!(f, " {}", diagnostic.concise_message())?; + write!(f, " {}", diagnostic.concise_message())?; + + // After rendering the main diagnostic, render its secondary annotations and + // sub-diagnostics. Note that lines within a single diagnostic must be separated by + // URL-encoded newlines (`%0A`) to render properly in GitHub annotations. + for annotation in diagnostic.secondary_annotations().filter_map(|annotation| { + GithubAnnotation::from_annotation(annotation, self.resolver) + }) { + write!(f, "%0A{annotation}")?; + } + + for subdiagnostic in diagnostic.sub_diagnostics() { + let severity = match subdiagnostic.severity() { + SubDiagnosticSeverity::Help => "help", + SubDiagnosticSeverity::Info => "info", + SubDiagnosticSeverity::Warning => "warning", + SubDiagnosticSeverity::Error | SubDiagnosticSeverity::Fatal => "error", + }; + if let Some(annotation) = subdiagnostic.primary_annotation() + && let span = annotation.get_span() + && let file = span.file() + && let Some(range) = span.range() + { + let diagnostic_source = file.diagnostic_source(self.resolver); + let source_code = diagnostic_source.as_source_code(); + let message = subdiagnostic.concise_message(); + let start_location = source_code.line_column(range.start()); + write!( + f, + "%0A {path}:{row}:{column}: {severity}: {message}", + path = file.relative_path(self.resolver).display(), + row = start_location.line, + column = start_location.column, + )?; + } else { + write!(f, "%0A {severity}: {}", subdiagnostic.concise_message())?; + } + + for annotation in subdiagnostic + .secondary_annotations() + .filter_map(|annotation| { + GithubAnnotation::from_annotation(annotation, self.resolver) + }) + { + write!(f, "%0A {annotation}")?; + } + } + + writeln!(f)?; } Ok(()) } } +struct GithubAnnotation<'a> { + message: &'a str, + range: TextRange, + file: &'a UnifiedFile, + resolver: &'a dyn FileResolver, +} + +impl<'a> GithubAnnotation<'a> { + fn from_annotation(annotation: &'a Annotation, resolver: &'a dyn FileResolver) -> Option { + let span = annotation.get_span(); + Some(Self { + message: annotation.get_message()?, + range: span.range()?, + file: span.file(), + resolver, + }) + } +} + +impl std::fmt::Display for GithubAnnotation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let diagnostic_source = self.file.diagnostic_source(self.resolver); + let source_code = diagnostic_source.as_source_code(); + let start_location = source_code.line_column(self.range.start()); + write!( + f, + " {path}:{row}:{column}:", + path = self.file.relative_path(self.resolver).display(), + row = start_location.line, + column = start_location.column, + )?; + + write!(f, " {message}", message = self.message) + } +} + #[cfg(test)] mod tests { use crate::diagnostic::{ diff --git a/crates/ruff_db/src/diagnostic/render/junit.rs b/crates/ruff_db/src/diagnostic/render/junit.rs index 1b964aafc9c5f..c24947bbd1218 100644 --- a/crates/ruff_db/src/diagnostic/render/junit.rs +++ b/crates/ruff_db/src/diagnostic/render/junit.rs @@ -184,9 +184,7 @@ impl std::io::Write for FmtAdapter<'_> { mod tests { use crate::diagnostic::{ DiagnosticFormat, - render::tests::{ - create_diagnostics, create_sub_diagnostics, create_syntax_error_diagnostics, - }, + render::tests::{create_diagnostics, create_syntax_error_diagnostics}, }; #[test] @@ -195,12 +193,6 @@ mod tests { insta::assert_snapshot!(env.render_diagnostics(&diagnostics)); } - #[test] - fn sub_diagnostics() { - let (env, diagnostics) = create_sub_diagnostics(DiagnosticFormat::Junit); - insta::assert_snapshot!(env.render_diagnostics(&diagnostics)); - } - #[test] fn syntax_errors() { let (env, diagnostics) = create_syntax_error_diagnostics(DiagnosticFormat::Junit); diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__azure__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__azure__tests__output.snap index c4b0a974118d2..dd4ab6aa3dd5b 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__azure__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__azure__tests__output.snap @@ -5,3 +5,4 @@ expression: env.render_diagnostics(&diagnostics) ##vso[task.logissue type=error;sourcepath=/fib.py;linenumber=1;columnnumber=8;code=F401;]`os` imported but unused ##vso[task.logissue type=error;sourcepath=/fib.py;linenumber=6;columnnumber=5;code=F841;]Local variable `x` is assigned to but never used ##vso[task.logissue type=error;sourcepath=/undef.py;linenumber=1;columnnumber=4;code=F821;]Undefined name `a` +##vso[task.logissue type=error;sourcepath=/fib.py;linenumber=12;columnnumber=16;code=F821;]Undefined name `fibonaccii` diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__github__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__github__tests__output.snap index 9ec5483c55efd..d0c6ea9e159c7 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__github__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__github__tests__output.snap @@ -2,6 +2,7 @@ source: crates/ruff_db/src/diagnostic/render/github.rs expression: env.render_diagnostics(&diagnostics) --- -::error title=ty (F401),file=/fib.py,line=1,col=8,endLine=1,endColumn=10::fib.py:1:8: F401 `os` imported but unused -::error title=ty (F841),file=/fib.py,line=6,col=5,endLine=6,endColumn=6::fib.py:6:5: F841 Local variable `x` is assigned to but never used +::error title=ty (F401),file=/fib.py,line=1,col=8,endLine=1,endColumn=10::fib.py:1:8: F401 `os` imported but unused%0A help: Remove unused import: `os` +::error title=ty (F841),file=/fib.py,line=6,col=5,endLine=6,endColumn=6::fib.py:6:5: F841 Local variable `x` is assigned to but never used%0A help: Remove assignment to unused variable `x` ::error title=ty (F821),file=/undef.py,line=1,col=4,endLine=1,endColumn=5::undef.py:1:4: F821 Undefined name `a` +::error title=ty (F821),file=/fib.py,line=12,col=16,endLine=12,endColumn=26::fib.py:12:16: F821 Undefined name `fibonaccii`%0A fib.py:4:5: info: Did you mean to import it from `/some/path/def.py`?: `fibonacci` is defined here%0A fib.py:5:5: `fibonacci` is documented here diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__gitlab__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__gitlab__tests__output.snap index a50787f92833e..47ff72bd44c1d 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__gitlab__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__gitlab__tests__output.snap @@ -59,5 +59,24 @@ expression: env.render_diagnostics(&diagnostics) } } } + }, + { + "check_name": "F821", + "description": "F821: Undefined name `fibonaccii`", + "severity": "major", + "fingerprint": "", + "location": { + "path": "fib.py", + "positions": { + "begin": { + "line": 12, + "column": 16 + }, + "end": { + "line": 12, + "column": 26 + } + } + } } ] diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json__tests__output.snap index 3ede6ee332f72..79fea8b21074f 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json__tests__output.snap @@ -85,5 +85,22 @@ expression: env.render_diagnostics(&diagnostics) "message": "Undefined name `a`", "noqa_row": 1, "url": "https://docs.astral.sh/ruff/rules/undefined-name" + }, + { + "cell": null, + "code": "F821", + "end_location": { + "column": 26, + "row": 12 + }, + "filename": "/fib.py", + "fix": null, + "location": { + "column": 16, + "row": 12 + }, + "message": "Undefined name `fibonaccii`", + "noqa_row": 1, + "url": "https://docs.astral.sh/ruff/rules/undefined-name" } ] diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json_lines__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json_lines__tests__output.snap index 8649d8bcb1773..5623ed9ec25a3 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json_lines__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__json_lines__tests__output.snap @@ -5,3 +5,4 @@ expression: env.render_diagnostics(&diagnostics) {"cell":null,"code":"F401","end_location":{"column":10,"row":1},"filename":"/fib.py","fix":{"applicability":"unsafe","edits":[{"content":"","end_location":{"column":1,"row":2},"location":{"column":1,"row":1}}],"message":"Remove unused import: `os`"},"location":{"column":8,"row":1},"message":"`os` imported but unused","noqa_row":1,"url":"https://docs.astral.sh/ruff/rules/unused-import"} {"cell":null,"code":"F841","end_location":{"column":6,"row":6},"filename":"/fib.py","fix":{"applicability":"unsafe","edits":[{"content":"","end_location":{"column":10,"row":6},"location":{"column":5,"row":6}}],"message":"Remove assignment to unused variable `x`"},"location":{"column":5,"row":6},"message":"Local variable `x` is assigned to but never used","noqa_row":6,"url":"https://docs.astral.sh/ruff/rules/unused-variable"} {"cell":null,"code":"F821","end_location":{"column":5,"row":1},"filename":"/undef.py","fix":null,"location":{"column":4,"row":1},"message":"Undefined name `a`","noqa_row":1,"url":"https://docs.astral.sh/ruff/rules/undefined-name"} +{"cell":null,"code":"F821","end_location":{"column":26,"row":12},"filename":"/fib.py","fix":null,"location":{"column":16,"row":12},"message":"Undefined name `fibonaccii`","noqa_row":1,"url":"https://docs.astral.sh/ruff/rules/undefined-name"} diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__output.snap index 767b620fb2b63..575975d1d5ca0 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__output.snap @@ -3,14 +3,17 @@ source: crates/ruff_db/src/diagnostic/render/junit.rs expression: env.render_diagnostics(&diagnostics) --- - - + + line 1, col 8, `os` imported but unused line 6, col 5, Local variable `x` is assigned to but never used + + line 12, col 16, Undefined name `fibonaccii` + diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__sub_diagnostics.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__sub_diagnostics.snap deleted file mode 100644 index 7e78c35ed4c47..0000000000000 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__junit__tests__sub_diagnostics.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: crates/ruff_db/src/diagnostic/render/junit.rs -expression: env.render_diagnostics(&diagnostics) ---- - - - - - line 1, col 1, Undefined name `f` - - - diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__pylint__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__pylint__tests__output.snap index 5d51a37c40601..94251302974ba 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__pylint__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__pylint__tests__output.snap @@ -5,3 +5,4 @@ expression: env.render_diagnostics(&diagnostics) fib.py:1: [F401] `os` imported but unused fib.py:6: [F841] Local variable `x` is assigned to but never used undef.py:1: [F821] Undefined name `a` +fib.py:12: [F821] Undefined name `fibonaccii` diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__rdjson__tests__output.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__rdjson__tests__output.snap index b20cf986d192b..fb230732b78ec 100644 --- a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__rdjson__tests__output.snap +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__rdjson__tests__output.snap @@ -93,6 +93,26 @@ expression: env.render_diagnostics(&diagnostics) } }, "message": "Undefined name `a`" + }, + { + "code": { + "url": "https://docs.astral.sh/ruff/rules/undefined-name", + "value": "F821" + }, + "location": { + "path": "/fib.py", + "range": { + "end": { + "column": 26, + "line": 12 + }, + "start": { + "column": 16, + "line": 12 + } + } + }, + "message": "Undefined name `fibonaccii`" } ], "severity": "WARNING", diff --git a/crates/ty/tests/cli/main.rs b/crates/ty/tests/cli/main.rs index f1c1e84cae980..a741f4ef29897 100644 --- a/crates/ty/tests/cli/main.rs +++ b/crates/ty/tests/cli/main.rs @@ -109,8 +109,8 @@ fn test_output_format_env() -> anyhow::Result<()> { success: false exit_code: 1 ----- stdout ----- - ::warning title=ty (unresolved-reference),file=/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined - ::error title=ty (not-subscriptable),file=/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + ::warning title=ty (unresolved-reference),file=/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined%0A info: rule `unresolved-reference` was selected on the command line + ::error title=ty (not-subscriptable),file=/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method%0A info: rule `not-subscriptable` is enabled by default ::notice title=ty (revealed-type),file=/test.py,line=5,col=13,endLine=5,endColumn=26::test.py:5:13: revealed-type: Revealed type: `LiteralString` ----- stderr ----- @@ -794,8 +794,8 @@ fn github_diagnostics() -> anyhow::Result<()> { success: false exit_code: 1 ----- stdout ----- - ::warning title=ty (unresolved-reference),file=/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined - ::error title=ty (not-subscriptable),file=/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method + ::warning title=ty (unresolved-reference),file=/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined%0A info: rule `unresolved-reference` was selected on the command line + ::error title=ty (not-subscriptable),file=/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method%0A info: rule `not-subscriptable` is enabled by default ::notice title=ty (revealed-type),file=/test.py,line=5,col=13,endLine=5,endColumn=26::test.py:5:13: revealed-type: Revealed type: `LiteralString` ----- stderr -----