Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/diagnostic.rs (Rust)

Code before:
    ///         return self.x == other.x
    /// ```
    ///
    /// If `A.__eq__` here were annotated as only accepting `A` instances for its second argument,
    /// it would imply that you wouldn't be able to use `==` between instances of `A` and
    /// instances of unrelated classes without an exception possibly being raised. While some
    /// classes in Python do indeed behave this way, the strongly held convention is that it should
    /// be avoided wherever possible. As part of this check, therefore, ty enforces that `__eq__`
    /// and `__ne__` methods accept `object` as their second argument.
    ///
    /// [Liskov Substitution Principle]: https://en.wikipedia.org/wiki/Liskov_substitution_principle
    pub(crate) static INVALID_METHOD_OVERRIDE = {
        summary: "detects method definitions that violate the Liskov Substitution Principle",
        status: LintStatus::stable("0.0.1-alpha.20"),
        default_level: Level::Error,
    }
}

/// A collection of type check diagnostics.
#[derive(Default, Eq, PartialEq, get_size2::GetSize)]
pub struct TypeCheckDiagnostics {
    diagnostics: Vec<Diagnostic>,
    used_suppressions: FxHashSet<FileSuppressionId>,
}

impl TypeCheckDiagnostics {
    pub(crate) fn push(&mut self, diagnostic: Diagnostic) {
        self.diagnostics.push(diagnostic);
    }

    pub(super) fn extend(&mut self, other: &TypeCheckDiagnostics) {
        self.diagnostics.extend_from_slice(&other.diagnostics);
        self.used_suppressions.extend(&other.used_suppressions);
    }

    pub(super) fn extend_diagnostics(&mut self, diagnostics: impl IntoIterator<Item = Diagnostic>) {
        self.diagnostics.extend(diagnostics);
    }

    pub(crate) fn mark_used(&mut self, suppression_id: FileSuppressionId) {
        self.used_suppressions.insert(suppression_id);
    }

    pub(crate) fn is_used(&self, suppression_id: FileSuppressionId) -> bool {
        self.used_suppressions.contains(&suppression_id)
    }

    pub(crate) fn used_len(&self) -> usize {
        self.used_suppressions.len()
    }


Review comment (suggestion):
Someday this will no longer be required, because Ruff could check itself whether this is an overriden method.

Code after:
    ///         return self.x == other.x
    /// ```
    ///
    /// If `A.__eq__` here were annotated as only accepting `A` instances for its second argument,
    /// it would imply that you wouldn't be able to use `==` between instances of `A` and
    /// instances of unrelated classes without an exception possibly being raised. While some
    /// classes in Python do indeed behave this way, the strongly held convention is that it should
    /// be avoided wherever possible. As part of this check, therefore, ty enforces that `__eq__`
    /// and `__ne__` methods accept `object` as their second argument.
    ///
    /// ### Why does ty disagree with Ruff about how to write my method?
    ///
    /// Ruff has several rules that will encourage you to rename a parameter, or change its type
    /// signature, if it thinks you're falling into a certain anti-pattern. For example, Ruff's
    /// [ARG002](https://docs.astral.sh/ruff/rules/unused-method-argument/) rule recommends that an
    /// unused parameter should either be removed or renamed to start with `_`. Applying either of
    /// these suggestions can cause ty to start reporting an `invalid-method-override` error if
    /// the function in question is a method on a subclass that overrides a method on a superclass,
    /// and the change would cause the subclass method to no longer accept all argument combinations
    /// that the superclass method accepts.
    ///
    /// This can usually be resolved by adding [`@typing.override`][override] to your method
    /// definition. Ruff knows that a method decorated with `@typing.override` is intended to
    /// override a method by the same name on a superclass, and avoids reporting rules like ARG002
    /// for such methods; it knows that the changes recommended by ARG002 would violate the Liskov
    /// Substitution Principle.
    ///
    /// Correct use of `@override` is enforced by ty's `invalid-explicit-override` rule.
    ///
    /// [Liskov Substitution Principle]: https://en.wikipedia.org/wiki/Liskov_substitution_principle
    /// [override]: https://docs.python.org/3/library/typing.html#typing.override
    pub(crate) static INVALID_METHOD_OVERRIDE = {
        summary: "detects method definitions that violate the Liskov Substitution Principle",
        status: LintStatus::stable("0.0.1-alpha.20"),
        default_level: Level::Error,
    }
}

/// A collection of type check diagnostics.
#[derive(Default, Eq, PartialEq, get_size2::GetSize)]
pub struct TypeCheckDiagnostics {
    diagnostics: Vec<Diagnostic>,
    used_suppressions: FxHashSet<FileSuppressionId>,
}

impl TypeCheckDiagnostics {
    pub(crate) fn push(&mut self, diagnostic: Diagnostic) {
        self.diagnostics.push(diagnostic);
    }

    pub(super) fn extend(&mut self, other: &TypeCheckDiagnostics) {