Class: Necropsy::AstScanner

Inherits:
Object
  • Object
show all
Defined in:
lib/necropsy/ast_scanner.rb,
lib/necropsy/ast_scanner/traversal.rb,
lib/necropsy/ast_scanner/dsl_macros.rb,
lib/necropsy/ast_scanner/references.rb,
lib/necropsy/ast_scanner/call_recording.rb,
lib/necropsy/ast_scanner/ruby_semantics.rb,
lib/necropsy/ast_scanner/value_definitions.rb,
lib/necropsy/ast_scanner/call_site_creation.rb,
lib/necropsy/ast_scanner/method_definitions.rb,
lib/necropsy/ast_scanner/definition_creation.rb

Defined Under Namespace

Classes: CallTraversal, Context

Constant Summary collapse

ATTR_MACROS =
%i[attr_reader attr_writer attr_accessor].freeze
DYNAMIC_SENDS =
%i[send public_send __send__].freeze
MODULE_RELATION_MACROS =
%i[include prepend extend].freeze
RAILS_CALLBACK_MACROS =
%i[
  before_action after_action around_action
  before_validation after_validation before_save after_save around_save
  around_validation before_touch after_touch
  before_enqueue around_enqueue after_enqueue before_perform around_perform after_perform
  before_create after_create around_create before_update after_update around_update
  before_destroy after_destroy around_destroy after_commit after_rollback after_initialize after_find
  after_create_commit after_update_commit after_destroy_commit after_save_commit
  validate rescue_from helper_method
].freeze
RAILS_GENERATED_METHOD_MACROS =
%i[
  enum store store_accessor attribute class_attribute mattr_reader mattr_writer mattr_accessor
  cattr_reader cattr_writer cattr_accessor belongs_to has_one has_many scope
].freeze
RAILS_RUNTIME_BLOCK_MACROS =
%i[discard_on retry_on stream_for stream_from].freeze
SIDEKIQ_RUNTIME_BLOCK_MACROS =
%i[sidekiq_retries_exhausted sidekiq_retry_in].freeze
VISIBILITY_MACROS =
%i[public protected private public_class_method private_class_method].freeze
SYMBOL_REFERENCE_CALLS =
%i[method respond_to? try try!].freeze
ANCESTRY_CONTROL_FLOW_TYPES =
%i[
  and_node block_node case_match_node case_node else_node for_node if_node in_node lambda_node
  or_node rescue_modifier_node rescue_node until_node when_node while_node
].freeze
RAILS_BUILTIN_VALIDATORS =
%w[
  absence acceptance allow_blank allow_nil comparison confirmation exclusion format if inclusion length message numericality
  on presence strict uniqueness unless
].freeze
RESPOND_TO_TRUTHY_LITERAL_TYPES =
%i[
  array_node float_node hash_node imaginary_node integer_node
  interpolated_match_last_line_node interpolated_regular_expression_node
  interpolated_string_node interpolated_symbol_node interpolated_x_string_node
  keyword_hash_node match_last_line_node range_node rational_node
  regular_expression_node source_encoding_node source_file_node source_line_node
  string_node symbol_node true_node x_string_node
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(project:, files:, source_domains: nil, scope_diagnostics: {}) ⇒ AstScanner

Returns a new instance of AstScanner.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/necropsy/ast_scanner.rb', line 87

def initialize(project:, files:, source_domains: nil, scope_diagnostics: {})
  @project = project
  @files = files
  @source_domains = source_domains || files.to_h { |file| [project.relative_path(file), :analyze] }
  @scope_diagnostics = scope_diagnostics
  @nodes = []
  @call_sites = []
  @instantiated_classes = Set.new
  @uncertainties = Hash.new { |hash, key| hash[key] = [] }
  @class_data = {}
  @entrypoint_hints = []
  @file_statuses = {}
  @source_errors = []
  @definition_ordinals = Hash.new(0)
  @call_site_ordinals = Hash.new(0)
  @module_function_sources = {}
  @deferred_module_functions = {}
  @method_signatures = {}
  @semantic_blockers = []
  @factory_methods = project.config.factory_methods.to_set(&:to_s)
  @convention_rules = ConventionRules.new
end

Instance Method Details

#scanObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/necropsy/ast_scanner.rb', line 110

def scan
  files.sort_by { |file| project.relative_path(file) }.each { |file| scan_file(file) }
  resolve_deferred_module_function_sources
  copy_module_function_call_sites
  ScanResult.new(
    nodes: nodes,
    call_sites: call_sites,
    instantiated_classes: instantiated_classes,
    uncertainties: uncertainties,
    class_infos: class_infos,
    entrypoint_hints: entrypoint_hints.uniq,
    file_statuses: file_statuses,
    source_errors: source_errors,
    source_domains: source_domains,
    scope_diagnostics: scope_diagnostics,
    method_signatures: method_signatures,
    semantic_blockers: semantic_blockers.sort_by { |blocker| BoundedCanonicalizer.dump(blocker.to_h) }
  )
end