Skip to content

Commit

Permalink
[red-knot] Allow any Ranged argument for report_lint and `report_…
Browse files Browse the repository at this point in the history
…diagnostic`
  • Loading branch information
MichaReiser committed Feb 19, 2025
1 parent e84985e commit 25cce39
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 215 deletions.
6 changes: 1 addition & 5 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2264,11 +2264,7 @@ impl<'db> InvalidTypeExpressionError<'db> {
invalid_expressions,
} = self;
for error in invalid_expressions {
context.report_lint(
&INVALID_TYPE_FORM,
node.into(),
format_args!("{}", error.reason()),
);
context.report_lint(&INVALID_TYPE_FORM, node, format_args!("{}", error.reason()));
}
fallback_type
}
Expand Down
63 changes: 38 additions & 25 deletions crates/red_knot_python_semantic/src/types/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use ruff_db::{
diagnostic::{DiagnosticId, Severity},
files::File,
};
use ruff_python_ast::AnyNodeRef;
use ruff_text_size::Ranged;
use ruff_text_size::{Ranged, TextRange};

use super::{binding_type, KnownFunction, TypeCheckDiagnostic, TypeCheckDiagnostics};

Expand Down Expand Up @@ -67,46 +66,60 @@ impl<'db> InferContext<'db> {
self.diagnostics.get_mut().extend(other.diagnostics());
}

/// Reports a lint located at `node`.
pub(super) fn report_lint(
/// Reports a lint located at `ranged`.
pub(super) fn report_lint<T>(
&self,
lint: &'static LintMetadata,
node: AnyNodeRef,
ranged: T,
message: fmt::Arguments,
) {
if !self.db.is_file_open(self.file) {
return;
}
) where
T: Ranged,
{
fn lint_severity(
context: &InferContext,
lint: &'static LintMetadata,
range: TextRange,
) -> Option<Severity> {
if !context.db.is_file_open(context.file) {
return None;
}

// Skip over diagnostics if the rule is disabled.
let Some(severity) = self.db.rule_selection().severity(LintId::of(lint)) else {
return;
};
// Skip over diagnostics if the rule is disabled.
let severity = context.db.rule_selection().severity(LintId::of(lint))?;

if self.is_in_no_type_check() {
return;
}
if context.is_in_no_type_check() {
return None;
}

let suppressions = suppressions(self.db, self.file);
let suppressions = suppressions(context.db, context.file);

if let Some(suppression) = suppressions.find_suppression(node.range(), LintId::of(lint)) {
self.diagnostics.borrow_mut().mark_used(suppression.id());
return;
if let Some(suppression) = suppressions.find_suppression(range, LintId::of(lint)) {
context.diagnostics.borrow_mut().mark_used(suppression.id());
return None;
}

Some(severity)
}

self.report_diagnostic(node, DiagnosticId::Lint(lint.name()), severity, message);
let Some(severity) = lint_severity(self, lint, ranged.range()) else {
return;
};

self.report_diagnostic(ranged, DiagnosticId::Lint(lint.name()), severity, message);
}

/// Adds a new diagnostic.
///
/// The diagnostic does not get added if the rule isn't enabled for this file.
pub(super) fn report_diagnostic(
pub(super) fn report_diagnostic<T>(
&self,
node: AnyNodeRef,
ranged: T,
id: DiagnosticId,
severity: Severity,
message: fmt::Arguments,
) {
) where
T: Ranged,
{
if !self.db.is_file_open(self.file) {
return;
}
Expand All @@ -121,7 +134,7 @@ impl<'db> InferContext<'db> {
file: self.file,
id,
message: message.to_string(),
range: node.range(),
range: ranged.range(),
severity,
});
}
Expand Down
14 changes: 7 additions & 7 deletions crates/red_knot_python_semantic/src/types/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ pub(super) fn report_possibly_unresolved_reference(

context.report_lint(
&POSSIBLY_UNRESOLVED_REFERENCE,
expr_name_node.into(),
expr_name_node,
format_args!("Name `{id}` used when possibly not defined"),
);
}
Expand All @@ -1058,15 +1058,15 @@ pub(super) fn report_unresolved_reference(context: &InferContext, expr_name_node

context.report_lint(
&UNRESOLVED_REFERENCE,
expr_name_node.into(),
expr_name_node,
format_args!("Name `{id}` used when not defined"),
);
}

pub(super) fn report_invalid_exception_caught(context: &InferContext, node: &ast::Expr, ty: Type) {
context.report_lint(
&INVALID_EXCEPTION_CAUGHT,
node.into(),
node,
format_args!(
"Cannot catch object of type `{}` in an exception handler \
(must be a `BaseException` subclass or a tuple of `BaseException` subclasses)",
Expand All @@ -1078,7 +1078,7 @@ pub(super) fn report_invalid_exception_caught(context: &InferContext, node: &ast
pub(crate) fn report_invalid_exception_raised(context: &InferContext, node: &ast::Expr, ty: Type) {
context.report_lint(
&INVALID_RAISE,
node.into(),
node,
format_args!(
"Cannot raise object of type `{}` (must be a `BaseException` subclass or instance)",
ty.display(context.db())
Expand All @@ -1089,7 +1089,7 @@ pub(crate) fn report_invalid_exception_raised(context: &InferContext, node: &ast
pub(crate) fn report_invalid_exception_cause(context: &InferContext, node: &ast::Expr, ty: Type) {
context.report_lint(
&INVALID_RAISE,
node.into(),
node,
format_args!(
"Cannot use object of type `{}` as exception cause \
(must be a `BaseException` subclass or instance or `None`)",
Expand All @@ -1101,7 +1101,7 @@ pub(crate) fn report_invalid_exception_cause(context: &InferContext, node: &ast:
pub(crate) fn report_base_with_incompatible_slots(context: &InferContext, node: &ast::Expr) {
context.report_lint(
&INCOMPATIBLE_SLOTS,
node.into(),
node,
format_args!("Class base has incompatible `__slots__`"),
);
}
Expand All @@ -1113,7 +1113,7 @@ pub(crate) fn report_invalid_arguments_to_annotated<'db>(
) {
context.report_lint(
&INVALID_TYPE_FORM,
subscript.into(),
subscript,
format_args!(
"Special form `{}` expected at least 2 arguments (one type and at least one metadata element)",
KnownInstanceType::Annotated.repr(db)
Expand Down
Loading

0 comments on commit 25cce39

Please sign in to comment.