Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/pylint/rules/import_private_name.rs (Rust)

Code before:
        };

        // Ignore private imports used exclusively for typing.
        if !binding.references.is_empty()
            && binding
                .references()
                .map(|reference_id| checker.semantic().reference(reference_id))
                .all(is_typing)
        {
            continue;
        }

        let name = (*private_name).to_string();
        let module = if index > 0 {
            Some(import_info.qualified_name.segments()[..index].join("."))
        } else {
            None
        };
        let range = match binding.source.map(|id| checker.semantic().statement(id)) {
            Some(ast::Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. })) => {
                if index < import_info.module_name.len() {
                    module.as_ref().map_or(binding.range(), |module| {
                        let offset: TextSize = import_info.qualified_name.segments()[..index]
                            .iter()
                            .map(|segment| segment.text_len() + TextSize::new(1))
                            .sum();

                        TextRange::at(module.start() + offset, private_name.text_len())
                    })
                } else {
                    names
                        .iter()
                        .find(|alias| alias.name.as_str() == import_info.member_name)
                        .map_or(binding.range(), |alias| alias.name.range())
                }
            }
            _ => binding.range(),
        };

        checker.report_diagnostic(ImportPrivateName { name, module }, range);
    }
}

/// Returns `true` if the [`ResolvedReference`] is in a typing context.
fn is_typing(reference: &ResolvedReference) -> bool {
    reference.in_type_checking_block()
        || reference.in_typing_only_annotation()
        || reference.in_string_type_definition()
        || reference.in_runtime_evaluated_annotation()
}


Review comment (refactor):
This is not quite right, see the new test case I added. I think we may want to find the next token using some code similar to this:

https://github.com/astral-sh/ruff/blob/b6f5b5a675bbe11cc70b5c30f61688144f3b500a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_with.rs#L168-L174

Code after:
            continue;
        };

        // Ignore private imports used exclusively for typing.
        if !binding.references.is_empty()
            && binding
                .references()
                .map(|reference_id| checker.semantic().reference(reference_id))
                .all(is_typing)
        {
            continue;
        }

        let name = (*private_name).to_string();
        let module = if index > 0 {
            Some(import_info.qualified_name.segments()[..index].join("."))
        } else {
            None
        };
        let range = match binding.source.map(|id| checker.semantic().statement(id)) {
            Some(ast::Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. })) => {
                if index < import_info.module_name.len() {
                    module.as_ref().map_or(binding.range(), |module| {
                        SimpleTokenizer::starts_at(module.start(), checker.locator().contents())
                            .skip_trivia()
                            .find(|token| {
                                token.kind == SimpleTokenKind::Name
                                    && checker.locator().slice(token.range()) == *private_name
                            })
                            .map_or(binding.range(), |token| token.range())
                    })
                } else {
                    names
                        .iter()
                        .find(|alias| alias.name.as_str() == import_info.member_name)
                        .map_or(binding.range(), |alias| alias.name.range())
                }
            }
            _ => binding.range(),
        };

        checker.report_diagnostic(ImportPrivateName { name, module }, range);
    }
}

/// Returns `true` if the [`ResolvedReference`] is in a typing context.
fn is_typing(reference: &ResolvedReference) -> bool {
    reference.in_type_checking_block()
        || reference.in_typing_only_annotation()
        || reference.in_string_type_definition()
        || reference.in_runtime_evaluated_annotation()