Class: Hind::LSIF::GlobalState

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/hind/lsif/global_state.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGlobalState

Returns a new instance of GlobalState.



13
14
15
# File 'lib/hind/lsif/global_state.rb', line 13

def initialize
  reset
end

Instance Attribute Details

#classesObject (readonly)

Returns the value of attribute classes.



11
12
13
# File 'lib/hind/lsif/global_state.rb', line 11

def classes
  @classes
end

#constantsObject (readonly)

Returns the value of attribute constants.



11
12
13
# File 'lib/hind/lsif/global_state.rb', line 11

def constants
  @constants
end

#modulesObject (readonly)

Returns the value of attribute modules.



11
12
13
# File 'lib/hind/lsif/global_state.rb', line 11

def modules
  @modules
end

#project_idObject

Returns the value of attribute project_id.



10
11
12
# File 'lib/hind/lsif/global_state.rb', line 10

def project_id
  @project_id
end

#rangesObject (readonly)

Returns the value of attribute ranges.



11
12
13
# File 'lib/hind/lsif/global_state.rb', line 11

def ranges
  @ranges
end

#referencesObject (readonly)

Returns the value of attribute references.



11
12
13
# File 'lib/hind/lsif/global_state.rb', line 11

def references
  @references
end

#result_setsObject (readonly)

Returns the value of attribute result_sets.



11
12
13
# File 'lib/hind/lsif/global_state.rb', line 11

def result_sets
  @result_sets
end

Instance Method Details

#add_ancestor(qualified_name, mixed_in_module, type) ⇒ Object



68
69
70
71
# File 'lib/hind/lsif/global_state.rb', line 68

def add_ancestor(qualified_name, mixed_in_module, type)
  @ancestors[qualified_name] ||= []
  @ancestors[qualified_name] << { name: mixed_in_module, type: type }
end

#add_class(qualified_name, data) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/hind/lsif/global_state.rb', line 30

def add_class(qualified_name, data)
  # Initialize if this is the first time we're seeing this class
  if !@classes.key?(qualified_name)
    @classes[qualified_name] = {definitions: []}
  end

  # Add this definition to the list
  @classes[qualified_name][:definitions] << data

  # Update the result set ID (we'll use the one from the primary definition)
  primary_def = determine_primary_class_definition(qualified_name)
  @result_sets[qualified_name] = primary_def[:result_set_id] if primary_def && primary_def[:result_set_id]
end

#add_constant(qualified_name, data) ⇒ Object



58
59
60
61
# File 'lib/hind/lsif/global_state.rb', line 58

def add_constant(qualified_name, data)
  @constants[qualified_name] = data
  @result_sets[qualified_name] = data[:result_set_id] if data[:result_set_id]
end

#add_method(qualified_name, data) ⇒ Object



63
64
65
66
# File 'lib/hind/lsif/global_state.rb', line 63

def add_method(qualified_name, data)
  @methods[qualified_name] = data
  @result_sets[qualified_name] = data[:result_set_id] if data[:result_set_id]
end

#add_module(qualified_name, data) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/hind/lsif/global_state.rb', line 44

def add_module(qualified_name, data)
  # Initialize if this is the first time we're seeing this module
  if !@modules.key?(qualified_name)
    @modules[qualified_name] = {definitions: []}
  end

  # Add this definition to the list
  @modules[qualified_name][:definitions] << data

  # Update the result set ID (we'll use the one from the primary definition)
  primary_def = determine_primary_module_definition(qualified_name)
  @result_sets[qualified_name] = primary_def[:result_set_id] if primary_def && primary_def[:result_set_id]
end

#add_range(file_path, range_id, location = nil) ⇒ Object



82
83
84
85
86
87
88
89
90
91
# File 'lib/hind/lsif/global_state.rb', line 82

def add_range(file_path, range_id, location = nil)
  @ranges[file_path] ||= []
  @ranges[file_path] << range_id

  if location
    @range_cache[file_path] ||= {}
    coords = [location.start_line, location.start_column, location.end_line, location.end_column]
    @range_cache[file_path][coords] = range_id
  end
end

#add_reference(qualified_name, file_path, range_id, document_id) ⇒ Object



73
74
75
76
77
78
79
80
# File 'lib/hind/lsif/global_state.rb', line 73

def add_reference(qualified_name, file_path, range_id, document_id)
  @references[qualified_name] ||= []
  @references[qualified_name] << {
    file: file_path,
    range_id: range_id,
    document_id: document_id
  }
end

#debug_infoObject



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/hind/lsif/global_state.rb', line 172

def debug_info
  {
    classes_count: @classes.size,
    modules_count: @modules.size,
    constants_count: @constants.size,
    references_count: @references.values.sum(&:size),
    result_sets_count: @result_sets.size,
    ranges_count: @ranges.values.sum(&:size),
    open_classes_count: @classes.count { |_, data| data[:definitions].size > 1 },
    open_modules_count: @modules.count { |_, data| data[:definitions].size > 1 }
  }
end

#find_constant_declaration(name, current_scope) ⇒ Object



168
169
170
# File 'lib/hind/lsif/global_state.rb', line 168

def find_constant_declaration(name, current_scope)
  find_declaration(name, current_scope)
end

#find_declaration(name, current_scope) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/hind/lsif/global_state.rb', line 130

def find_declaration(name, current_scope)
  # Handle both constants (::) and methods (#)
  is_method = name.start_with?('#')
  sep = is_method ? '' : '::'

  # 1. Lexical Scope search
  # Try full current scope
  qualified_name = current_scope.empty? ? name : "#{current_scope}#{sep}#{name}"
  # Strip leading # if simple name
  qualified_name = name if current_scope.empty? && is_method
  return qualified_name if has_declaration?(qualified_name)

  # 2. Ancestor chain search for current scope
  if !current_scope.empty?
    found = resolve_in_ancestors(name, current_scope, seen: Set.new)
    return found if found
  end

  # 3. Parent Lexical Scopes
  scope_parts = current_scope.split('::')
  while scope_parts.size > 0
    scope_parts.pop
    prefix = scope_parts.join('::')

    qualified_name = prefix.empty? ? name : "#{prefix}#{sep}#{name}"
    qualified_name = name if prefix.empty? && is_method
    return qualified_name if has_declaration?(qualified_name)

    # Search ancestors of the parent scope too
    if !prefix.empty?
      found = resolve_in_ancestors(name, prefix, seen: Set.new)
      return found if found
    end
  end

  nil
end

#find_range_id(file_path, location) ⇒ Object



93
94
95
96
97
# File 'lib/hind/lsif/global_state.rb', line 93

def find_range_id(file_path, location)
  return nil unless @range_cache[file_path] && location
  coords = [location.start_line, location.start_column, location.end_line, location.end_column]
  @range_cache[file_path][coords]
end

#get_class_definitions(qualified_name) ⇒ Object

Returns all definitions for a class



186
187
188
189
# File 'lib/hind/lsif/global_state.rb', line 186

def get_class_definitions(qualified_name)
  return [] unless @classes.key?(qualified_name)
  @classes[qualified_name][:definitions]
end

#get_declaration(qualified_name) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/hind/lsif/global_state.rb', line 106

def get_declaration(qualified_name)
  if @classes.key?(qualified_name)
    determine_primary_class_definition(qualified_name)
  elsif @modules.key?(qualified_name)
    determine_primary_module_definition(qualified_name)
  elsif @constants.key?(qualified_name)
    @constants[qualified_name]
  else
    @methods[qualified_name]
  end
end

#get_module_definitions(qualified_name) ⇒ Object

Returns all definitions for a module



192
193
194
195
# File 'lib/hind/lsif/global_state.rb', line 192

def get_module_definitions(qualified_name)
  return [] unless @modules.key?(qualified_name)
  @modules[qualified_name][:definitions]
end

#get_ranges_for_file(file_path) ⇒ Object



126
127
128
# File 'lib/hind/lsif/global_state.rb', line 126

def get_ranges_for_file(file_path)
  @ranges[file_path] || []
end

#get_references(qualified_name) ⇒ Object



118
119
120
# File 'lib/hind/lsif/global_state.rb', line 118

def get_references(qualified_name)
  @references[qualified_name] || []
end

#get_result_set(qualified_name) ⇒ Object



122
123
124
# File 'lib/hind/lsif/global_state.rb', line 122

def get_result_set(qualified_name)
  @result_sets[qualified_name]
end

#has_declaration?(qualified_name) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
102
103
104
# File 'lib/hind/lsif/global_state.rb', line 99

def has_declaration?(qualified_name)
  @classes.key?(qualified_name) ||
    @modules.key?(qualified_name) ||
    @constants.key?(qualified_name) ||
    @methods.key?(qualified_name)
end

#resetObject



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/hind/lsif/global_state.rb', line 17

def reset
  @classes = {}     # {qualified_name => {definitions: [{node:, scope:, file:, range_id:, result_set_id:, superclass:}]}}
  @modules = {}     # {qualified_name => {definitions: [{node:, scope:, file:, range_id:, result_set_id:}]}}
  @constants = {}   # {qualified_name => {node:, scope:, file:, range_id:, result_set_id:, value:}}
  @methods = {}     # {qualified_name => {node:, scope:, file:, range_id:, result_set_id:}}
  @references = {}  # {qualified_name => [{file:, range_id:, document_id:}, ...]}
  @ranges = {}      # {file_path => [range_ids]}
  @range_cache = {} # {file_path => {[start_line, start_col, end_line, end_col] => range_id}}
  @result_sets = {} # {qualified_name => result_set_id}
  @ancestors = {}   # {qualified_name => [{name:, type:}]}
  @project_id = nil
end