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

Code before:
        );

        builder
    }

    fn current_scope_info(&self) -> &ScopeInfo {
        self.scope_stack
            .last()
            .expect("SemanticIndexBuilder should have created a root scope")
    }

    fn current_scope_info_mut(&mut self) -> &mut ScopeInfo {
        self.scope_stack
            .last_mut()
            .expect("SemanticIndexBuilder should have created a root scope")
    }

    fn current_scope(&self) -> FileScopeId {
        self.current_scope_info().file_scope_id
    }

    /// Returns the scope ID of the method scope if the current scope
    /// is a method inside a class body. Returns `None` otherwise, e.g. if the current
    /// scope is a function body outside of a class, or if the current scope is not a
    /// function body.
    fn is_method_of_class(&self) -> Option<FileScopeId> {
        let mut scopes_rev = self
            .scope_stack
            .iter()
            .rev()
            .skip_while(|scope| self.scopes[scope.file_scope_id].is_eager());
        let current = scopes_rev.next()?;

        if self.scopes[current.file_scope_id].kind() != ScopeKind::Function {
            return None;
        }

        let maybe_method = current.file_scope_id;
        let parent = scopes_rev.next()?;

        match self.scopes[parent.file_scope_id].kind() {
            ScopeKind::Class => Some(maybe_method),
            ScopeKind::TypeParams => {
                // If the function is generic, the parent scope is an annotation scope.
                // In this case, we need to go up one level higher to find the class scope.
                let grandparent = scopes_rev.next()?;

                if self.scopes[grandparent.file_scope_id].kind() == ScopeKind::Class {
                    Some(maybe_method)
                } else {
                    None

Review comment (suggestion):
This function is also used at https://github.com/Glyphack/ruff/blob/8d53802bc7e9566a9087fd3e3a460345e40a7e6d/crates/ty_python_semantic/src/semantic_index/builder.rs#L1681 and I think this new behavior should be there as well.
I'm not happy with the name though, this now returns either method or an eager child scope of the class.

Code after:
        builder.push_scope_with_parent(
            NodeWithScopeRef::Module,
            None,
            ScopedReachabilityConstraintId::ALWAYS_TRUE,
        );

        builder
    }

    fn current_scope_info(&self) -> &ScopeInfo {
        self.scope_stack
            .last()
            .expect("SemanticIndexBuilder should have created a root scope")
    }

    fn current_scope_info_mut(&mut self) -> &mut ScopeInfo {
        self.scope_stack
            .last_mut()
            .expect("SemanticIndexBuilder should have created a root scope")
    }

    fn current_scope(&self) -> FileScopeId {
        self.current_scope_info().file_scope_id
    }

    /// Returns the scope ID of the current scope if the current scope
    /// is a method inside a class body or an eagerly executed scope inside a method.
    /// Returns `None` otherwise, e.g. if the current scope is a function body outside of a class, or if the current scope is not a
    /// function body.
    fn is_method_or_eagerly_executed_in_method(&self) -> Option<FileScopeId> {
        let mut scopes_rev = self
            .scope_stack
            .iter()
            .rev()
            .skip_while(|scope| self.scopes[scope.file_scope_id].is_eager());
        let current = scopes_rev.next()?;

        if self.scopes[current.file_scope_id].kind() != ScopeKind::Function {
            return None;
        }

        let maybe_method = current.file_scope_id;
        let parent = scopes_rev.next()?;

        match self.scopes[parent.file_scope_id].kind() {
            ScopeKind::Class => Some(maybe_method),
            ScopeKind::TypeParams => {
                // If the function is generic, the parent scope is an annotation scope.
                // In this case, we need to go up one level higher to find the class scope.
                let grandparent = scopes_rev.next()?;