Class: Audition::Static::Checks::UnshareableReads

Inherits:
Base
  • Object
show all
Defined in:
lib/audition/static/checks/unshareable_reads.rb

Overview

Constants known to hold unshareable objects. Their definitions live outside the scanned tree (or are swept from it at setup), so the read site is the only place a static pass can flag. Learned type aliases match only in Sorbet type positions, where a constant can only name a type—a class sharing a name stays quiet. Namespaces that build constants with const_set at boot get their constant reads flagged too: the values never pass through a literal the analyzer could classify.

Constant Summary collapse

KNOWN =
Ractor.make_shareable(
  {"T::Boolean" => :sorbet_type_alias}
)
ALIAS_DEFINITION =

Stub generators write rbi definitions fully qualified on one line, so a regex sweep is enough there.

/^\s*((?:[A-Z]\w*::)*[A-Z]\w*)\s*=\s*T\.type_alias\b/
VALUE_NAME =
/\A[A-Z][A-Z0-9_]*\z/

Constants inherited from Base

Base::EMPTY_CATALOG, Base::WRAPPER

Class Attribute Summary collapse

Attributes inherited from Base

#file, #findings

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

call, check_name, explain, explanations, handlers, on

Constructor Details

#initialize(file) ⇒ UnshareableReads

Returns a new instance of UnshareableReads.



173
174
175
176
# File 'lib/audition/static/checks/unshareable_reads.rb', line 173

def initialize(file)
  super
  @typed = Set.new
end

Class Attribute Details

.dynamic ⇒ Object

Returns the value of attribute dynamic.



58
59
60
# File 'lib/audition/static/checks/unshareable_reads.rb', line 58

def dynamic
  @dynamic
end

.learned ⇒ Object

Returns the value of attribute learned.



58
59
60
# File 'lib/audition/static/checks/unshareable_reads.rb', line 58

def learned
  @learned
end

Class Method Details

.learn(paths, progress: Progress::SILENT) ⇒ Object

Sweeps the tree for type-alias assignments and for namespaces that const_set under a computed name. Ruby sources are parsed so definitions keep their nesting; rbi files are line-scanned.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/audition/static/checks/unshareable_reads.rb', line 79

def learn(paths, progress: Progress::SILENT)
  aliases = []
  owners = []
  paths.each do |path|
    progress.tick
    source = begin
      File.read(path)
    rescue SystemCallError
      next
    end
    if path.end_with?(".rbi")
      source.scan(ALIAS_DEFINITION) do |(name)|
        aliases << name.split("::")
      end
    else
      result = Prism.parse(source)
      next unless result.success?

      sweep(result.value, [], aliases, owners)
    end
  end
  self.learned = aliases
  self.dynamic = owners
end