Class: Rigor::Inference::ProtectionScanner

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/inference/protection_scanner.rb

Overview

ADR-63 Tier 1 — the static type-protection proxy. Walks every dispatch site (a method call with an explicit receiver) and classifies it by whether the receiver types to a concrete (non-‘Dynamic`) type — i.e. a site where Rigor’s call rules can bite (undefined-method / wrong-arity / argument-type-mismatch). A ‘Dynamic` / `Top` receiver (or a union with such an arm — gradually valid) is unprotected: Rigor is blind there, and a type annotation on it would buy real catching power.

This is a sound UPPER BOUND on protection — a concrete receiver is necessary but not sufficient for a diagnostic to actually fire — and it is one ‘type_of` pass, so it runs interactively and in CI. The truth tier (does a diagnostic fire) is the phased mutation tier.

Defined Under Namespace

Classes: FileResult, Site

Instance Method Summary collapse

Constructor Details

#initialize(scope: nil) ⇒ ProtectionScanner

Returns a new instance of ProtectionScanner.



32
33
34
# File 'lib/rigor/inference/protection_scanner.rb', line 32

def initialize(scope: nil)
  @scope = scope || Scope.empty
end

Instance Method Details

#scan(root) ⇒ FileResult

Parameters:

  • root (Prism::Node)

    the parsed AST

Returns:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rigor/inference/protection_scanner.rb', line 38

def scan(root)
  index = ScopeIndexer.index(root, default_scope: @scope)
  protected_count = 0
  sites = []

  Source::NodeWalker.each(root) do |node|
    next unless dispatch_site?(node)

    receiver_type = index[node.receiver].type_of(node.receiver)
    if concrete_receiver?(receiver_type)
      protected_count += 1
    else
      sites << Site.new(
        line: node.location.start_line,
        receiver: safe_describe(receiver_type),
        method_name: node.name.to_s
      )
    end
  end

  FileResult.new(protected_count: protected_count, unprotected_count: sites.size, sites: sites)
end