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

Code before:
    // references in __all__ refer to typing-only imports, the __getattr__ might be
    // able to handle that attribute access and return the correct thing at runtime.
    let ignore_dunder_all_references = checker
        .semantic()
        .lookup_symbol_in_scope("__getattr__", ScopeId::global(), false)
        .is_some();

    for binding_id in scope.binding_ids() {
        let binding = checker.semantic().binding(binding_id);

        let Some(import) = binding.as_any_import() else {
            continue;
        };

        let Some(reference_id) = binding.references.first().copied() else {
            continue;
        };

        let runtime_refs: Vec<_> = binding
            .references()
            .filter(|&reference_id| {
                let reference = checker.semantic().reference(reference_id);
                reference.in_runtime_context()
                    && !(ignore_dunder_all_references && reference.in_dunder_all_definition())
            })
            .collect();

        if runtime_refs.is_empty() {
            continue;
        }

        let runtime_info = runtime_refs
            .split_first()
            .map(|(first, rest)| RuntimeInformation {
                first_reference: *first,
                count: 1 + rest.len(),
            });

        if binding.context.is_typing() {
            let Some(node_id) = binding.source else {
                continue;
            };

            let import = ImportBinding {
                import,
                reference_id,
                binding,
                range: binding.range(),
                parent_range: binding.parent_range(checker.semantic()),
                needs_future_import: false, // TODO(brent) See #19359.
            };

Review comment (suggestion):
The `count` field is a nice touch, but I don't think it's worth allocating a `Vec` here. I think flagging the first runtime reference with a secondary annotation is enough.

Code after:

                (reference.in_runtime_context()
                    && !(ignore_dunder_all_references && reference.in_dunder_all_definition()))
                .then_some(reference)
            })
        {
            let Some(node_id) = binding.source else {
                continue;
            };

            let import = ImportBinding {
                import,
                reference_id,
                binding,
                range: binding.range(),
                parent_range: binding.parent_range(checker.semantic()),
                needs_future_import: false, // TODO(brent) See #19359.
                runtime_reference: Some(runtime_reference),
            };

            if checker.rule_is_ignored(Rule::RuntimeImportInTypeCheckingBlock, import.start())
                || import.parent_range.is_some_and(|parent_range| {
                    checker.rule_is_ignored(
                        Rule::RuntimeImportInTypeCheckingBlock,
                        parent_range.start(),
                    )
                })
            {
                actions
                    .entry((node_id, Action::Ignore))
                    .or_default()
                    .push(import);
            } else {
                // Determine whether the member should be fixed by moving the import out of the
                // type-checking block, or by quoting its references.
                // TODO: We should check `reference.in_annotated_type_alias()`
                //       as well to match the behavior of the flake8 plugin
                //       although maybe the best way forward is to add an
                //       additional setting to configure whether quoting
                //       or moving the import is preferred for type aliases
                //       since some people will consistently use their
                //       type aliases at runtimes, while others won't, so
                //       the best solution is unclear.
                if checker.settings().flake8_type_checking.quote_annotations
                    && binding.references().all(|reference_id| {
                        let reference = checker.semantic().reference(reference_id);
                        reference.in_typing_context() || reference.in_runtime_evaluated_annotation()
                    })
                {
                    actions
                        .entry((node_id, Action::Quote))