Skip to content

Commit 1ae2f54

Browse files
committed
Merge remote-tracking branch 'origin/main' into dcreager/promote-literals
* origin/main: [ty] Add hint that PEP 604 union syntax is only available in 3.10+ (#18192) Unify `Message` variants (#18051) [`airflow`] Update `AIR301` and `AIR311` with the latest Airflow implementations (#17985) [`airflow`] Move rules from `AIR312` to `AIR302` (#17940) [ty] Small LSP cleanups (#18201) [ty] Show related information in diagnostic (#17359) Default `src.root` to `['.', '<project_name>']` if the directory exists (#18141)
2 parents d308a3a + 0ede831 commit 1ae2f54

File tree

64 files changed

+1594
-1125
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1594
-1125
lines changed

crates/ruff/src/cache.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ use itertools::Itertools;
1313
use log::{debug, error};
1414
use rayon::iter::ParallelIterator;
1515
use rayon::iter::{IntoParallelIterator, ParallelBridge};
16-
use ruff_linter::{codes::Rule, registry::AsRule};
16+
use ruff_linter::codes::Rule;
1717
use rustc_hash::FxHashMap;
1818
use tempfile::NamedTempFile;
1919

2020
use ruff_cache::{CacheKey, CacheKeyHasher};
2121
use ruff_diagnostics::Fix;
22-
use ruff_linter::message::{DiagnosticMessage, Message};
22+
use ruff_linter::message::Message;
2323
use ruff_linter::package::PackageRoot;
2424
use ruff_linter::{VERSION, warn_user};
2525
use ruff_macros::CacheKey;
2626
use ruff_notebook::NotebookIndex;
2727
use ruff_source_file::SourceFileBuilder;
28-
use ruff_text_size::{TextRange, TextSize};
28+
use ruff_text_size::{Ranged, TextRange, TextSize};
2929
use ruff_workspace::Settings;
3030
use ruff_workspace::resolver::Resolver;
3131

@@ -348,16 +348,16 @@ impl FileCache {
348348
lint.messages
349349
.iter()
350350
.map(|msg| {
351-
Message::Diagnostic(DiagnosticMessage {
352-
name: msg.rule.into(),
353-
body: msg.body.clone(),
354-
suggestion: msg.suggestion.clone(),
355-
range: msg.range,
356-
fix: msg.fix.clone(),
357-
file: file.clone(),
358-
noqa_offset: msg.noqa_offset,
359-
parent: msg.parent,
360-
})
351+
Message::diagnostic(
352+
msg.rule.into(),
353+
msg.body.clone(),
354+
msg.suggestion.clone(),
355+
msg.range,
356+
msg.fix.clone(),
357+
msg.parent,
358+
file.clone(),
359+
msg.noqa_offset,
360+
)
361361
})
362362
.collect()
363363
};
@@ -439,22 +439,22 @@ impl LintCacheData {
439439

440440
let messages = messages
441441
.iter()
442-
.filter_map(|message| message.as_diagnostic_message())
443-
.map(|msg| {
442+
.filter_map(|msg| msg.to_rule().map(|rule| (rule, msg)))
443+
.map(|(rule, msg)| {
444444
// Make sure that all message use the same source file.
445445
assert_eq!(
446-
msg.file,
446+
msg.source_file(),
447447
messages.first().unwrap().source_file(),
448448
"message uses a different source file"
449449
);
450450
CacheMessage {
451-
rule: msg.rule(),
452-
body: msg.body.clone(),
453-
suggestion: msg.suggestion.clone(),
454-
range: msg.range,
451+
rule,
452+
body: msg.body().to_string(),
453+
suggestion: msg.suggestion().map(ToString::to_string),
454+
range: msg.range(),
455455
parent: msg.parent,
456-
fix: msg.fix.clone(),
457-
noqa_offset: msg.noqa_offset,
456+
fix: msg.fix().cloned(),
457+
noqa_offset: msg.noqa_offset(),
458458
}
459459
})
460460
.collect();
@@ -485,7 +485,7 @@ pub(super) struct CacheMessage {
485485
#[bincode(with_serde)]
486486
fix: Option<Fix>,
487487
#[bincode(with_serde)]
488-
noqa_offset: TextSize,
488+
noqa_offset: Option<TextSize>,
489489
}
490490

491491
pub(crate) trait PackageCaches {

crates/ruff/src/commands/check.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use ruff_linter::settings::types::UnsafeFixes;
2020
use ruff_linter::settings::{LinterSettings, flags};
2121
use ruff_linter::{IOError, fs, warn_user_once};
2222
use ruff_source_file::SourceFileBuilder;
23-
use ruff_text_size::{TextRange, TextSize};
23+
use ruff_text_size::TextRange;
2424
use ruff_workspace::resolver::{
2525
PyprojectConfig, ResolvedFile, match_exclusion, python_files_in_path,
2626
};
@@ -133,7 +133,7 @@ pub(crate) fn check(
133133
vec![Message::from_diagnostic(
134134
Diagnostic::new(IOError { message }, TextRange::default()),
135135
dummy,
136-
TextSize::default(),
136+
None,
137137
)],
138138
FxHashMap::default(),
139139
)

crates/ruff/src/diagnostics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use ruff_linter::{IOError, fs};
2525
use ruff_notebook::{Notebook, NotebookError, NotebookIndex};
2626
use ruff_python_ast::{PySourceType, SourceType, TomlSourceType};
2727
use ruff_source_file::SourceFileBuilder;
28-
use ruff_text_size::{TextRange, TextSize};
28+
use ruff_text_size::TextRange;
2929
use ruff_workspace::Settings;
3030

3131
use crate::cache::{Cache, FileCacheKey, LintCacheData};
@@ -71,7 +71,7 @@ impl Diagnostics {
7171
TextRange::default(),
7272
),
7373
source_file,
74-
TextSize::default(),
74+
None,
7575
)],
7676
FxHashMap::default(),
7777
)

crates/ruff/src/printer.rs

Lines changed: 22 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
use std::cmp::Reverse;
2-
use std::fmt::Display;
32
use std::hash::Hash;
43
use std::io::Write;
54

65
use anyhow::Result;
76
use bitflags::bitflags;
87
use colored::Colorize;
98
use itertools::{Itertools, iterate};
9+
use ruff_linter::codes::NoqaCode;
1010
use serde::Serialize;
1111

1212
use ruff_linter::fs::relativize_path;
1313
use ruff_linter::logging::LogLevel;
1414
use ruff_linter::message::{
1515
AzureEmitter, Emitter, EmitterContext, GithubEmitter, GitlabEmitter, GroupedEmitter,
16-
JsonEmitter, JsonLinesEmitter, JunitEmitter, Message, MessageKind, PylintEmitter,
17-
RdjsonEmitter, SarifEmitter, TextEmitter,
16+
JsonEmitter, JsonLinesEmitter, JunitEmitter, Message, PylintEmitter, RdjsonEmitter,
17+
SarifEmitter, TextEmitter,
1818
};
1919
use ruff_linter::notify_user;
20-
use ruff_linter::registry::Rule;
2120
use ruff_linter::settings::flags::{self};
2221
use ruff_linter::settings::types::{OutputFormat, UnsafeFixes};
2322

@@ -37,59 +36,12 @@ bitflags! {
3736

3837
#[derive(Serialize)]
3938
struct ExpandedStatistics {
40-
code: Option<SerializeRuleAsCode>,
41-
name: SerializeMessageKindAsTitle,
39+
code: Option<NoqaCode>,
40+
name: &'static str,
4241
count: usize,
4342
fixable: bool,
4443
}
4544

46-
#[derive(Copy, Clone)]
47-
struct SerializeRuleAsCode(Rule);
48-
49-
impl Serialize for SerializeRuleAsCode {
50-
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
51-
where
52-
S: serde::Serializer,
53-
{
54-
serializer.serialize_str(&self.0.noqa_code().to_string())
55-
}
56-
}
57-
58-
impl Display for SerializeRuleAsCode {
59-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60-
write!(f, "{}", self.0.noqa_code())
61-
}
62-
}
63-
64-
impl From<Rule> for SerializeRuleAsCode {
65-
fn from(rule: Rule) -> Self {
66-
Self(rule)
67-
}
68-
}
69-
70-
struct SerializeMessageKindAsTitle(MessageKind);
71-
72-
impl Serialize for SerializeMessageKindAsTitle {
73-
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
74-
where
75-
S: serde::Serializer,
76-
{
77-
serializer.serialize_str(self.0.as_str())
78-
}
79-
}
80-
81-
impl Display for SerializeMessageKindAsTitle {
82-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83-
f.write_str(self.0.as_str())
84-
}
85-
}
86-
87-
impl From<MessageKind> for SerializeMessageKindAsTitle {
88-
fn from(kind: MessageKind) -> Self {
89-
Self(kind)
90-
}
91-
}
92-
9345
pub(crate) struct Printer {
9446
format: OutputFormat,
9547
log_level: LogLevel,
@@ -350,21 +302,25 @@ impl Printer {
350302
let statistics: Vec<ExpandedStatistics> = diagnostics
351303
.messages
352304
.iter()
353-
.sorted_by_key(|message| (message.rule(), message.fixable()))
354-
.fold(vec![], |mut acc: Vec<(&Message, usize)>, message| {
355-
if let Some((prev_message, count)) = acc.last_mut() {
356-
if prev_message.rule() == message.rule() {
357-
*count += 1;
358-
return acc;
305+
.map(|message| (message.to_noqa_code(), message))
306+
.sorted_by_key(|(code, message)| (*code, message.fixable()))
307+
.fold(
308+
vec![],
309+
|mut acc: Vec<((Option<NoqaCode>, &Message), usize)>, (code, message)| {
310+
if let Some(((prev_code, _prev_message), count)) = acc.last_mut() {
311+
if *prev_code == code {
312+
*count += 1;
313+
return acc;
314+
}
359315
}
360-
}
361-
acc.push((message, 1));
362-
acc
363-
})
316+
acc.push(((code, message), 1));
317+
acc
318+
},
319+
)
364320
.iter()
365-
.map(|&(message, count)| ExpandedStatistics {
366-
code: message.rule().map(std::convert::Into::into),
367-
name: message.kind().into(),
321+
.map(|&((code, message), count)| ExpandedStatistics {
322+
code,
323+
name: message.name(),
368324
count,
369325
fixable: if let Some(fix) = message.fix() {
370326
fix.applies(self.unsafe_fixes.required_applicability())

crates/ruff_db/src/diagnostic/mod.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,25 @@ impl Diagnostic {
249249
diagnostic: self,
250250
}
251251
}
252+
253+
/// Returns all annotations, skipping the first primary annotation.
254+
pub fn secondary_annotations(&self) -> impl Iterator<Item = &Annotation> {
255+
let mut seen_primary = false;
256+
self.inner.annotations.iter().filter(move |ann| {
257+
if seen_primary {
258+
true
259+
} else if ann.is_primary {
260+
seen_primary = true;
261+
false
262+
} else {
263+
true
264+
}
265+
})
266+
}
267+
268+
pub fn sub_diagnostics(&self) -> &[SubDiagnostic] {
269+
&self.inner.subs
270+
}
252271
}
253272

254273
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -371,6 +390,57 @@ impl SubDiagnostic {
371390
pub fn annotate(&mut self, ann: Annotation) {
372391
self.inner.annotations.push(ann);
373392
}
393+
394+
pub fn annotations(&self) -> &[Annotation] {
395+
&self.inner.annotations
396+
}
397+
398+
/// Returns a shared borrow of the "primary" annotation of this diagnostic
399+
/// if one exists.
400+
///
401+
/// When there are multiple primary annotations, then the first one that
402+
/// was added to this diagnostic is returned.
403+
pub fn primary_annotation(&self) -> Option<&Annotation> {
404+
self.inner.annotations.iter().find(|ann| ann.is_primary)
405+
}
406+
407+
/// Introspects this diagnostic and returns what kind of "primary" message
408+
/// it contains for concise formatting.
409+
///
410+
/// When we concisely format diagnostics, we likely want to not only
411+
/// include the primary diagnostic message but also the message attached
412+
/// to the primary annotation. In particular, the primary annotation often
413+
/// contains *essential* information or context for understanding the
414+
/// diagnostic.
415+
///
416+
/// The reason why we don't just always return both the main diagnostic
417+
/// message and the primary annotation message is because this was written
418+
/// in the midst of an incremental migration of ty over to the new
419+
/// diagnostic data model. At time of writing, diagnostics were still
420+
/// constructed in the old model where the main diagnostic message and the
421+
/// primary annotation message were not distinguished from each other. So
422+
/// for now, we carefully return what kind of messages this diagnostic
423+
/// contains. In effect, if this diagnostic has a non-empty main message
424+
/// *and* a non-empty primary annotation message, then the diagnostic is
425+
/// 100% using the new diagnostic data model and we can format things
426+
/// appropriately.
427+
///
428+
/// The type returned implements the `std::fmt::Display` trait. In most
429+
/// cases, just converting it to a string (or printing it) will do what
430+
/// you want.
431+
pub fn concise_message(&self) -> ConciseMessage {
432+
let main = self.inner.message.as_str();
433+
let annotation = self
434+
.primary_annotation()
435+
.and_then(|ann| ann.get_message())
436+
.unwrap_or_default();
437+
match (main.is_empty(), annotation.is_empty()) {
438+
(false, true) => ConciseMessage::MainDiagnostic(main),
439+
(true, false) => ConciseMessage::PrimaryAnnotation(annotation),
440+
(false, false) => ConciseMessage::Both { main, annotation },
441+
(true, true) => ConciseMessage::Empty,
442+
}
443+
}
374444
}
375445

376446
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -493,6 +563,11 @@ impl Annotation {
493563
&self.span
494564
}
495565

566+
/// Sets the span on this annotation.
567+
pub fn set_span(&mut self, span: Span) {
568+
self.span = span;
569+
}
570+
496571
/// Returns the tags associated with this annotation.
497572
pub fn get_tags(&self) -> &[DiagnosticTag] {
498573
&self.tags
@@ -616,7 +691,7 @@ impl DiagnosticId {
616691
///
617692
/// Note that this doesn't include the lint's category. It
618693
/// only includes the lint's name.
619-
pub fn as_str(&self) -> &str {
694+
pub fn as_str(&self) -> &'static str {
620695
match self {
621696
DiagnosticId::Panic => "panic",
622697
DiagnosticId::Io => "io",

crates/ruff_db/src/files.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use ruff_text_size::{Ranged, TextRange};
1111
use salsa::plumbing::AsId;
1212
use salsa::{Durability, Setter};
1313

14+
use crate::diagnostic::{Span, UnifiedFile};
1415
use crate::file_revision::FileRevision;
1516
use crate::files::file_root::FileRoots;
1617
use crate::files::private::FileStatus;
@@ -549,6 +550,29 @@ impl Ranged for FileRange {
549550
}
550551
}
551552

553+
impl TryFrom<&Span> for FileRange {
554+
type Error = ();
555+
556+
fn try_from(value: &Span) -> Result<Self, Self::Error> {
557+
let UnifiedFile::Ty(file) = value.file() else {
558+
return Err(());
559+
};
560+
561+
Ok(Self {
562+
file: *file,
563+
range: value.range().ok_or(())?,
564+
})
565+
}
566+
}
567+
568+
impl TryFrom<Span> for FileRange {
569+
type Error = ();
570+
571+
fn try_from(value: Span) -> Result<Self, Self::Error> {
572+
Self::try_from(&value)
573+
}
574+
}
575+
552576
#[cfg(test)]
553577
mod tests {
554578
use crate::file_revision::FileRevision;

0 commit comments

Comments
 (0)