solargraph 0.53.1 → 0.53.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb238e5ca67dae6ca26b2a5fb6eda261727eb6464f0c048adf1d043fb13ccacd
4
- data.tar.gz: dfc03ca7f87fe40f79ba387b4489be60f7f155b60e2e6a3fa696637684545501
3
+ metadata.gz: c5f84e528dd40d7638e36189ca6b4dceccdfd1722a07bd1c1f060bf0265aa815
4
+ data.tar.gz: 39d6938ccabce6dda403c709711f6136472def5982222e73d89310eaeb906ee1
5
5
  SHA512:
6
- metadata.gz: f101995ec1f808c69afbdb8be4d865159a6b349782b97ab7d6bb96dd61fd6ec43b8b3a3d7c9c55e14ee6feab4cdd7f570c9de688ff6a8a099f927a3d972a4e0a
7
- data.tar.gz: 82b02c423e72e482e93b314361eb7165898906c3d02221b4336af853645bc668bbbb7412298db2921b621e91c0baf294987cf0d16c2b878bb5ad3b57fd0d2f3b
6
+ metadata.gz: cf06b94032becde9f26b7d5cedcecbc0fd7d6bde539a980c748328f11165f91398605e7ff49af502b83a70a4aa9b32406c5846cda96f5246d20c97d17220700b
7
+ data.tar.gz: bdddccf5d52efd2a9be2b00ac473065ecca21d76646d59d247c5cb93b14de137ebfc16ec4ffbc3ed0d6e9de9f271e9763808775d6aa271496e6328bf70b443bf
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.53.3 - March 29, 2025
2
+ - Remove redundant core fills (#824, #841)
3
+ - Resolve self type in variable assignments (#839)
4
+ - Eliminate splat-related false-alarms in strict typechecking (#840)
5
+ - Dynamic block binding with yieldreceiver (#842)
6
+ - Resolve generics by descending through context type (#847)
7
+
8
+ ## 0.53.2 - March 27, 2025
9
+ - Fix a self-type-related false-positive in strict typechecking (#834)
10
+ - DocMap fetches gem dependencies (#835)
11
+ - Use configured command path to spawn solargraph processes (#837)
12
+
1
13
  ## 0.53.1 - March 26, 2025
2
14
  - Reject nil requires in live code (#831)
3
15
  - RbsMap adds mixins to current namespace (#832)
@@ -6,10 +6,13 @@ module Solargraph
6
6
 
7
7
  # Get the YARD CodeObject at the specified path.
8
8
  #
9
+ # @generic T
9
10
  # @param path [String]
10
- # @return [YARD::CodeObjects::Base]
11
- def code_object_at path
12
- code_object_map[path]
11
+ # @param klass [Class<generic<T>>]
12
+ # @return [generic<T>, nil]
13
+ def code_object_at path, klass = YARD::CodeObjects::Base
14
+ obj = code_object_map[path]
15
+ obj if obj&.is_a?(klass)
13
16
  end
14
17
 
15
18
  # @return [Array<String>]
@@ -41,11 +44,13 @@ module Solargraph
41
44
  end
42
45
  code_object_map[pin.path].docstring = pin.docstring
43
46
  store.get_includes(pin.path).each do |ref|
44
- code_object_map[pin.path].instance_mixins.push code_object_map[ref] unless code_object_map[ref].nil? or code_object_map[pin.path].nil?
47
+ include_object = code_object_at(pin.path, YARD::CodeObjects::ClassObject)
48
+ include_object.instance_mixins.push code_object_map[ref] unless include_object.nil? or include_object.nil?
45
49
  end
46
50
  store.get_extends(pin.path).each do |ref|
47
- code_object_map[pin.path].instance_mixins.push code_object_map[ref] unless code_object_map[ref].nil? or code_object_map[pin.path].nil?
48
- code_object_map[pin.path].class_mixins.push code_object_map[ref] unless code_object_map[ref].nil? or code_object_map[pin.path].nil?
51
+ extend_object = code_object_at(pin.path, YARD::CodeObjects::ClassObject)
52
+ extend_object.instance_mixins.push code_object_map[ref] unless extend_object.nil? or extend_object.nil?
53
+ extend_object.class_mixins.push code_object_map[ref] unless extend_object.nil? or extend_object.nil?
49
54
  end
50
55
  end
51
56
  store.method_pins.each do |pin|
@@ -53,13 +58,15 @@ module Solargraph
53
58
  code_object_map[pin.path] ||= pin.code_object
54
59
  next
55
60
  end
56
- code_object_map[pin.path] ||= YARD::CodeObjects::MethodObject.new(code_object_at(pin.namespace), pin.name, pin.scope) { |obj|
61
+
62
+ code_object_map[pin.path] ||= YARD::CodeObjects::MethodObject.new(code_object_at(pin.namespace, YARD::CodeObjects::NamespaceObject), pin.name, pin.scope) { |obj|
57
63
  next if pin.location.nil? || pin.location.filename.nil?
58
64
  obj.add_file pin.location.filename, pin.location.range.start.line
59
65
  }
60
- code_object_map[pin.path].docstring = pin.docstring
61
- code_object_map[pin.path].visibility = pin.visibility || :public
62
- code_object_map[pin.path].parameters = pin.parameters.map do |p|
66
+ method_object = code_object_at(pin.path, YARD::CodeObjects::MethodObject)
67
+ method_object.docstring = pin.docstring
68
+ method_object.visibility = pin.visibility || :public
69
+ method_object.parameters = pin.parameters.map do |p|
63
70
  [p.name, p.asgn_code]
64
71
  end
65
72
  end
@@ -64,11 +64,10 @@ module Solargraph
64
64
  implicit.merge map.environ
65
65
  end
66
66
  unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).uniq
67
- @doc_map = DocMap.new(unresolved_requires, []) # @todo Implement gem dependencies
67
+ @doc_map = DocMap.new(unresolved_requires, []) # @todo Implement gem preferences
68
68
  @store = Store.new(@@core_map.pins + @doc_map.pins + implicit.pins + pins)
69
69
  @unresolved_requires = @doc_map.unresolved_requires
70
70
  @missing_docs = [] # @todo Implement missing docs
71
- @rebindable_method_names = nil
72
71
  store.block_pins.each { |blk| blk.rebind(self) }
73
72
  self
74
73
  end
@@ -154,17 +153,6 @@ module Solargraph
154
153
  store.pins
155
154
  end
156
155
 
157
- # @return [Set<String>]
158
- def rebindable_method_names
159
- @rebindable_method_names ||= begin
160
- result = ['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec', 'define_method'].to_set
161
- source_maps.each do |map|
162
- result.merge map.rebindable_method_names
163
- end
164
- result
165
- end
166
- end
167
-
168
156
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
169
157
  #
170
158
  # @return [Enumerable<Solargraph::Pin::Keyword>]
@@ -8,7 +8,7 @@ module Solargraph
8
8
  class UniqueType
9
9
  include TypeMethods
10
10
 
11
- attr_reader :all_params
11
+ attr_reader :all_params, :subtypes, :key_types
12
12
 
13
13
  # Create a UniqueType with the specified name and an optional substring.
14
14
  # The substring is the parameter section of a parametrized type, e.g.,
@@ -105,13 +105,9 @@ module Solargraph
105
105
  # @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
106
106
  # @return [UniqueType, ComplexType]
107
107
  def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
108
- transform(name) do |t|
109
- next t unless t.name == ComplexType::GENERIC_TAG_NAME
110
-
111
- new_binding = false
112
-
113
- type_param = t.subtypes.first&.name
114
- next t unless generics_to_resolve.include? type_param
108
+ if name == ComplexType::GENERIC_TAG_NAME
109
+ type_param = subtypes.first&.name
110
+ return self unless generics_to_resolve.include? type_param
115
111
  unless context_type.nil? || !resolved_generic_values[type_param].nil?
116
112
  new_binding = true
117
113
  resolved_generic_values[type_param] = context_type
@@ -121,7 +117,34 @@ module Solargraph
121
117
  complex_type.resolve_generics_from_context(generics_to_resolve, nil, resolved_generic_values: resolved_generic_values)
122
118
  end
123
119
  end
124
- resolved_generic_values[type_param] || t
120
+ return resolved_generic_values[type_param] || self
121
+ end
122
+
123
+ # @todo typechecking should complain when the method being called has no @yieldparam tag
124
+ new_key_types = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:key_types)
125
+ new_subtypes = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:subtypes)
126
+ recreate(new_key_types: new_key_types, new_subtypes: new_subtypes)
127
+ end
128
+
129
+ # @param generics_to_resolve [Enumerable<String>]
130
+ # @param context_type [UniqueType]
131
+ # @param resolved_generic_values [Hash{String => ComplexType}]
132
+ # @yieldreturn [Array<ComplexType>]
133
+ # @return [Array<ComplexType>]
134
+ def resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values)
135
+ types = yield self
136
+ types.each_with_index.flat_map do |ct, i|
137
+ ct.items.flat_map do |ut|
138
+ context_params = yield context_type if context_type
139
+ if context_params && context_params[i]
140
+ type_arg = context_params[i]
141
+ type_arg.map do |new_unique_context_type|
142
+ ut.resolve_generics_from_context generics_to_resolve, new_unique_context_type, resolved_generic_values: resolved_generic_values
143
+ end
144
+ else
145
+ ut.resolve_generics_from_context generics_to_resolve, nil, resolved_generic_values: resolved_generic_values
146
+ end
147
+ end
125
148
  end
126
149
  end
127
150
 
@@ -8,7 +8,7 @@ module Solargraph
8
8
  attr_reader :requires
9
9
 
10
10
  # @return [Array<Gem::Specification>]
11
- attr_reader :dependencies
11
+ attr_reader :preferences
12
12
 
13
13
  # @return [Array<Pin::Base>]
14
14
  attr_reader :pins
@@ -17,10 +17,10 @@ module Solargraph
17
17
  attr_reader :uncached_gemspecs
18
18
 
19
19
  # @param requires [Array<String>]
20
- # @param dependencies [Array<Gem::Specification>]
21
- def initialize(requires, dependencies)
20
+ # @param preferences [Array<Gem::Specification>]
21
+ def initialize(requires, preferences)
22
22
  @requires = requires.compact
23
- @dependencies = dependencies.compact
23
+ @preferences = preferences.compact
24
24
  generate
25
25
  end
26
26
 
@@ -39,17 +39,11 @@ module Solargraph
39
39
  @gems_in_memory ||= {}
40
40
  end
41
41
 
42
- private
43
-
44
- # @return [Hash{String => Gem::Specification, nil}]
45
- def required_gem_map
46
- @required_gem_map ||= requires.to_h { |path| [path, resolve_path_to_gemspec(path)] }
42
+ def dependencies
43
+ @dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
47
44
  end
48
45
 
49
- # @return [Hash{String => Gem::Specification}]
50
- def dependency_map
51
- @dependency_map ||= dependencies.to_h { |gemspec| [gemspec.name, gemspec] }
52
- end
46
+ private
53
47
 
54
48
  # @return [void]
55
49
  def generate
@@ -62,6 +56,17 @@ module Solargraph
62
56
  try_stdlib_map path
63
57
  end
64
58
  end
59
+ dependencies.each { |dep| try_cache dep }
60
+ end
61
+
62
+ # @return [Hash{String => Gem::Specification, nil}]
63
+ def required_gem_map
64
+ @required_gem_map ||= requires.to_h { |path| [path, resolve_path_to_gemspec(path)] }
65
+ end
66
+
67
+ # @return [Hash{String => Gem::Specification}]
68
+ def preference_map
69
+ @preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
65
70
  end
66
71
 
67
72
  # @param gemspec [Gem::Specification]
@@ -123,16 +128,16 @@ module Solargraph
123
128
  nil
124
129
  end
125
130
  end
126
- return gemspec if dependencies.empty? || gemspec.nil?
131
+ gemspec_or_preference gemspec
132
+ end
127
133
 
128
- if dependency_map.key?(gemspec.name)
129
- return gemspec if gemspec.version == dependency_map[gemspec.name].version
134
+ # @param gemspec [Gem::Specification, nil]
135
+ # @return [Gem::Specification, nil]
136
+ def gemspec_or_preference gemspec
137
+ return gemspec unless gemspec && preference_map.key?(gemspec.name)
138
+ return gemspec if gemspec.version == preference_map[gemspec.name].version
130
139
 
131
- change_gemspec_version gemspec, dependency_map[by_path.name].version
132
- else
133
- Solargraph.logger.warn "Gem #{gemspec.name} is not an expected dependency"
134
- gemspec
135
- end
140
+ change_gemspec_version gemspec, preference_map[by_path.name].version
136
141
  end
137
142
 
138
143
  # @param gemspec [Gem::Specification]
@@ -144,5 +149,23 @@ module Solargraph
144
149
  Solargraph.logger.info "Gem #{gemspec.name} version #{version} not found. Using #{gemspec.version} instead"
145
150
  gemspec
146
151
  end
152
+
153
+ # @param gemspec [Gem::Specification]
154
+ # @return [Array<Gem::Specification>]
155
+ def fetch_dependencies gemspec
156
+ only_runtime_dependencies(gemspec).each_with_object(Set.new) do |spec, deps|
157
+ Solargraph.logger.info "Adding #{spec.name} dependency for #{gemspec.name}"
158
+ dep = Gem::Specification.find_by_name(spec.name, spec.requirement)
159
+ deps.merge fetch_dependencies(dep) if deps.add?(dep)
160
+ rescue Gem::MissingSpecError
161
+ Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirements} for #{gemspec.name} not found."
162
+ end.to_a
163
+ end
164
+
165
+ # @param gemspec [Gem::Specification]
166
+ # @return [Array<Gem::Dependency>]
167
+ def only_runtime_dependencies gemspec
168
+ gemspec.dependencies - gemspec.development_dependencies
169
+ end
147
170
  end
148
171
  end
@@ -20,7 +20,7 @@ module Solargraph
20
20
  combined = yard_pins.map do |yard|
21
21
  in_yard.add yard.path
22
22
  next yard unless yard.is_a?(Pin::Method)
23
- rbs = rbs_map.path_pin(yard.path)
23
+ rbs = rbs_map.path_pin(yard.path, Pin::Method)
24
24
  next yard unless rbs
25
25
  # @todo Could not include: attribute and anon_splat
26
26
  # @sg-ignore
@@ -95,6 +95,10 @@ module Solargraph
95
95
  nil
96
96
  end
97
97
 
98
+ def options
99
+ @options ||= {}.freeze
100
+ end
101
+
98
102
  # Get a generic library for the given URI and attach the corresponding
99
103
  # source.
100
104
  #
@@ -109,7 +113,7 @@ module Solargraph
109
113
 
110
114
  # @return [Library]
111
115
  def generic_library
112
- @generic_library ||= Solargraph::Library.new
116
+ @generic_library ||= Solargraph::Library.new(Solargraph::Workspace.new('', nil, options), nil)
113
117
  end
114
118
  end
115
119
  end
@@ -292,7 +292,8 @@ module Solargraph
292
292
  path = ''
293
293
  path = normalize_separators(directory) unless directory.nil?
294
294
  begin
295
- lib = Solargraph::Library.load(path, name)
295
+ workspace = Solargraph::Workspace.new(path, nil, options)
296
+ lib = Solargraph::Library.new(workspace, name)
296
297
  libraries.push lib
297
298
  async_library_map lib
298
299
  rescue WorkspaceTooLargeError => e
@@ -251,7 +251,19 @@ module Solargraph
251
251
  found = source.references(pin.name)
252
252
  found.select! do |loc|
253
253
  referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
254
- referenced && referenced.path == pin.path
254
+ referenced&.path == pin.path
255
+ end
256
+ if pin.path == 'Class#new'
257
+ caller = cursor.chain.base.infer(api_map, clip.send(:block), clip.locals).first
258
+ if caller.defined?
259
+ found.select! do |loc|
260
+ clip = api_map.clip_at(loc.filename, loc.range.start)
261
+ other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:block), clip.locals).first
262
+ caller == other
263
+ end
264
+ else
265
+ found.clear
266
+ end
255
267
  end
256
268
  # HACK: for language clients that exclude special characters from the start of variable names
257
269
  if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
@@ -603,7 +615,7 @@ module Solargraph
603
615
 
604
616
  logger.info "Caching #{spec.name} #{spec.version}"
605
617
  Thread.new do
606
- @cache_pid = Process.spawn('solargraph', 'cache', spec.name, spec.version.to_s)
618
+ @cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
607
619
  Process.wait(@cache_pid)
608
620
  logger.info "Cached #{spec.name} #{spec.version}"
609
621
  @synchronized = false
@@ -7,6 +7,12 @@ require 'cgi'
7
7
 
8
8
  module Solargraph
9
9
  class Page
10
+ # @todo This method directive is necessary because OpenStruct.new confuses
11
+ # the typechecker.
12
+ # @!method self.new(locals, render_method)
13
+ # @param locals[Hash]
14
+ # @param render_method [Proc]
15
+ # @return [Binder]
10
16
  class Binder < OpenStruct
11
17
  # @param locals [Hash]
12
18
  # @param render_method [Proc]
@@ -6,31 +6,18 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class DefNode < Parser::NodeProcessor::Base
8
8
  def process
9
+ name = node.children[0].to_s
10
+ scope = region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance)
9
11
  methpin = Solargraph::Pin::Method.new(
10
12
  location: get_node_location(node),
11
13
  closure: region.closure,
12
- name: node.children[0].to_s,
14
+ name: name,
13
15
  comments: comments_for(node),
14
- scope: region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance),
15
- visibility: region.visibility,
16
+ scope: scope,
17
+ visibility: scope == :instance && name == 'initialize' ? :private : region.visibility,
16
18
  node: node
17
19
  )
18
- if methpin.name == 'initialize' and methpin.scope == :instance
19
- pins.push Solargraph::Pin::Method.new(
20
- location: methpin.location,
21
- closure: methpin.closure,
22
- name: 'new',
23
- comments: methpin.comments,
24
- scope: :class,
25
- parameters: methpin.parameters
26
- )
27
- # @todo Smelly instance variable access.
28
- pins.last.instance_variable_set(:@return_type, ComplexType::SELF)
29
- pins.push methpin
30
- # @todo Smelly instance variable access.
31
- methpin.instance_variable_set(:@visibility, :private)
32
- methpin.instance_variable_set(:@return_type, ComplexType::VOID)
33
- elsif region.visibility == :module_function
20
+ if region.visibility == :module_function
34
21
  pins.push Solargraph::Pin::Method.new(
35
22
  location: methpin.location,
36
23
  closure: methpin.closure,
@@ -51,7 +51,7 @@ module Solargraph
51
51
  # Use the return node for inference. The clip might infer from the
52
52
  # first node in a method call instead of the entire call.
53
53
  chain = Parser.chain(node, nil, nil)
54
- result = chain.infer(api_map, closure, clip.locals)
54
+ result = chain.infer(api_map, closure, clip.locals).self_to(closure.context.tag)
55
55
  types.push result unless result.undefined?
56
56
  end
57
57
  end
@@ -47,36 +47,19 @@ module Solargraph
47
47
  # @return [ComplexType, nil]
48
48
  def binder_or_nil api_map
49
49
  return nil unless receiver
50
- word = receiver.children.find { |c| c.is_a?(::Symbol) }.to_s
51
- return nil unless api_map.rebindable_method_names.include?(word)
50
+
52
51
  chain = Parser.chain(receiver, location.filename)
53
52
  locals = api_map.source_map(location.filename).locals_at(location)
54
- links_last_word = chain.links.last.word
55
- if %w[instance_eval instance_exec class_eval class_exec module_eval module_exec].include?(links_last_word)
56
- return chain.base.infer(api_map, self, locals)
57
- end
58
- if 'define_method' == links_last_word and chain.define(api_map, self, locals).first&.path == 'Module#define_method' # change class type to instance type
59
- if chain.links.size > 1 # Class.define_method
60
- ty = chain.base.infer(api_map, self, locals)
61
- return Solargraph::ComplexType.parse(ty.namespace)
62
- else # define_method without self
63
- return Solargraph::ComplexType.parse(closure.binder.namespace)
64
- end
65
- end
66
- # other case without early return, read block yieldreceiver tags
67
53
  receiver_pin = chain.define(api_map, self, locals).first
68
- if receiver_pin && receiver_pin.docstring
69
- ys = receiver_pin.docstring.tag(:yieldreceiver)
70
- if ys && ys.types && !ys.types.empty?
71
- target = if chain.links.first.is_a?(Source::Chain::Constant)
72
- receiver_pin.full_context.namespace
73
- else
74
- full_context.namespace
75
- end
76
- return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace).self_to(target)
77
- end
78
- end
79
- nil
54
+ return nil unless receiver_pin
55
+
56
+ types = receiver_pin.docstring.tag(:yieldreceiver)&.types
57
+ return nil unless types&.any?
58
+
59
+ target = chain.base.infer(api_map, receiver_pin, locals)
60
+ target = full_context unless target.defined?
61
+
62
+ ComplexType.try_parse(*types).qualify(api_map, receiver_pin.context.namespace).self_to(target.to_s)
80
63
  end
81
64
  end
82
65
  end
@@ -38,25 +38,6 @@ module Solargraph
38
38
  environment = RBS::Environment.from_loader(loader).resolve_type_names
39
39
  cursor = pins.length
40
40
  environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
41
- added_pins = pins[cursor..-1]
42
- add_back_implicit_pins(added_pins)
43
- end
44
-
45
- # @param added_pins [::Enumerable<Pin>]
46
- # @return [void]
47
- def add_back_implicit_pins(added_pins)
48
- added_pins.each do |pin|
49
- pin.source = :rbs
50
- next unless pin.is_a?(Pin::Namespace) && pin.type == :class
51
- next if pins.any? { |p| p.path == "#{pin.path}.new"}
52
- pins.push Solargraph::Pin::Method.new(
53
- location: nil,
54
- closure: pin,
55
- name: 'new',
56
- comments: pin.comments,
57
- scope: :class
58
- )
59
- end
60
41
  end
61
42
 
62
43
  # @param decl [RBS::AST::Declarations::Base]
@@ -303,26 +284,8 @@ module Solargraph
303
284
  pin.signatures.concat method_def_to_sigs(decl, pin)
304
285
  pins.push pin
305
286
  if pin.name == 'initialize'
306
- pins.push Solargraph::Pin::Method.new(
307
- location: pin.location,
308
- closure: pin.closure,
309
- name: 'new',
310
- comments: pin.comments,
311
- scope: :class,
312
- signatures: pin.signatures
313
- )
314
- pins.last.signatures.replace(
315
- pin.signatures.map do |p|
316
- Pin::Signature.new(
317
- p.generics,
318
- p.parameters,
319
- ComplexType::SELF
320
- )
321
- end
322
- )
323
- # @todo Is this necessary?
324
- # pin.instance_variable_set(:@visibility, :private)
325
- # pin.instance_variable_set(:@return_type, ComplexType::VOID)
287
+ pin.instance_variable_set(:@visibility, :private)
288
+ pin.instance_variable_set(:@return_type, ComplexType::VOID)
326
289
  end
327
290
  end
328
291
  if decl.singleton?
@@ -22,11 +22,14 @@ module Solargraph
22
22
  closure: Solargraph::Pin::Namespace.new(name: 'Object'), comments: '@return [Class<self>]')
23
23
  ]
24
24
 
25
- CLASS_RETURN_TYPES = [
26
- Override.method_return('Class#new', 'self'),
27
- Override.method_return('Class.new', 'Class<BasicObject>'),
28
- Override.method_return('Class#allocate', 'self'),
29
- Override.method_return('Class.allocate', 'Class<BasicObject>')
25
+ OVERRIDES = [
26
+ Override.from_comment('BasicObject#instance_eval', '@yieldreceiver [self]'),
27
+ Override.from_comment('BasicObject#instance_exec', '@yieldreceiver [self]'),
28
+ Override.from_comment('Module#define_method', '@yieldreceiver [Object<self>]'),
29
+ Override.from_comment('Module#class_eval', '@yieldreceiver [Class<self>]'),
30
+ Override.from_comment('Module#class_exec', '@yieldreceiver [Class<self>]'),
31
+ Override.from_comment('Module#module_eval', '@yieldreceiver [Module<self>]'),
32
+ Override.from_comment('Module#module_exec', '@yieldreceiver [Module<self>]')
30
33
  ]
31
34
 
32
35
  # HACK: Add Errno exception classes
@@ -38,7 +41,7 @@ module Solargraph
38
41
  end
39
42
  ERRNOS = errnos
40
43
 
41
- ALL = KEYWORDS + MISSING + CLASS_RETURN_TYPES + ERRNOS
44
+ ALL = KEYWORDS + MISSING + OVERRIDES + ERRNOS
42
45
  end
43
46
  end
44
47
  end
@@ -13,27 +13,16 @@ module Solargraph
13
13
  pins.replace cache
14
14
  else
15
15
  loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
16
- environment = RBS::Environment.from_loader(loader).resolve_type_names
16
+ RBS::Environment.from_loader(loader).resolve_type_names
17
17
  load_environment_to_pins(loader)
18
18
  pins.concat RbsMap::CoreFills::ALL
19
19
  processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
20
+ processed.each { |pin| pin.source = :rbs }
20
21
  pins.replace processed
21
22
 
22
23
  Cache.save('core.ser', pins)
23
24
  end
24
25
  end
25
-
26
- def method_def_to_sigs decl, pin
27
- stubs = CoreSigns.sign(pin.path)
28
- return super unless stubs
29
- stubs.map do |stub|
30
- Pin::Signature.new(
31
- [],
32
- [],
33
- ComplexType.try_parse(stub.return_type)
34
- )
35
- end
36
- end
37
26
  end
38
27
  end
39
28
  end
@@ -7,7 +7,6 @@ module Solargraph
7
7
  autoload :Conversions, 'solargraph/rbs_map/conversions'
8
8
  autoload :CoreMap, 'solargraph/rbs_map/core_map'
9
9
  autoload :CoreFills, 'solargraph/rbs_map/core_fills'
10
- autoload :CoreSigns, 'solargraph/rbs_map/core_signs'
11
10
  autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
12
11
 
13
12
  include Conversions
@@ -28,10 +27,13 @@ module Solargraph
28
27
  load_environment_to_pins(loader)
29
28
  end
30
29
 
30
+ # @generic T
31
31
  # @param path [String]
32
- # @return [Pin::Base, nil]
33
- def path_pin path
34
- pins.find { |p| p.path == path }
32
+ # @param klass [Class<generic<T>>]
33
+ # @return [generic<T>, nil]
34
+ def path_pin path, klass = Pin::Base
35
+ pin = pins.find { |p| p.path == path }
36
+ pin if pin&.is_a?(klass)
35
37
  end
36
38
 
37
39
  # @param path [String]
@@ -50,9 +50,9 @@ module Solargraph
50
50
  def infer
51
51
  result = cursor.chain.infer(api_map, block, locals)
52
52
  if result.tag == 'Class'
53
- # HACK: Exception to return Object from Class#new
53
+ # HACK: Exception to return BasicObject from Class#new
54
54
  dfn = cursor.chain.define(api_map, block, locals).first
55
- return ComplexType.try_parse('Object') if dfn && dfn.path == 'Class#new'
55
+ return ComplexType.try_parse('BasicObject') if dfn && dfn.path == 'Class#new'
56
56
  end
57
57
  return result unless result.tag == 'self'
58
58
  ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).tag)
@@ -40,14 +40,6 @@ module Solargraph
40
40
  @pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
41
41
  end
42
42
 
43
- # @return [Set<String>]
44
- def rebindable_method_names
45
- @rebindable_method_names ||= pins_by_class(Pin::Method)
46
- .select { |pin| pin.comments && pin.comments.include?('@yieldreceiver') }
47
- .map(&:name)
48
- .to_set
49
- end
50
-
51
43
  # @return [String]
52
44
  def filename
53
45
  source.filename
@@ -299,6 +299,14 @@ module Solargraph
299
299
  pin = pins.first
300
300
  ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
301
301
  arity_problems_for(pin, fake_args_for(block_pin), location)
302
+ elsif pin.path == 'Class#new'
303
+ fqns = if base.links.one?
304
+ block_pin.namespace
305
+ else
306
+ base.base.infer(api_map, block_pin, locals).namespace
307
+ end
308
+ init = api_map.get_method_stack(fqns, 'initialize').first
309
+ init ? arity_problems_for(init, base.links.last.arguments, location) : []
302
310
  else
303
311
  arity_problems_for(pin, base.links.last.arguments, location)
304
312
  end
@@ -320,8 +328,14 @@ module Solargraph
320
328
  argchain = base.links.last.arguments[idx]
321
329
  if argchain.nil?
322
330
  if par.decl == :arg
323
- errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
324
- next
331
+ last = base.links.last.arguments.last
332
+ if last && last.node.type == :splat
333
+ argchain = last
334
+ next # don't try to apply the type of the splat - unlikely to be specific enough
335
+ else
336
+ errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
337
+ next
338
+ end
325
339
  else
326
340
  last = base.links.last.arguments.last
327
341
  argchain = last if last && [:kwsplat, :hash].include?(last.node.type)
@@ -332,7 +346,12 @@ module Solargraph
332
346
  errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
333
347
  next
334
348
  else
349
+ last = base.links.last.arguments.last
350
+ if last && last.node.type == :splat
351
+ next # don't try to apply the type of the splat - unlikely to be specific enough
352
+ end
335
353
  ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
354
+ ptype = ptype.self_to(par.context.namespace)
336
355
  if ptype.nil?
337
356
  # @todo Some level (strong, I guess) should require the param here
338
357
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.53.1'
4
+ VERSION = '0.53.3'
5
5
  end
@@ -25,9 +25,11 @@ module Solargraph
25
25
 
26
26
  # @param directory [String]
27
27
  # @param config [Config, nil]
28
- def initialize directory = '', config = nil
28
+ # @param server [Hash]
29
+ def initialize directory = '', config = nil, server = {}
29
30
  @directory = directory
30
31
  @config = config
32
+ @server = server
31
33
  load_sources
32
34
  @gemnames = []
33
35
  @require_paths = generate_require_paths
@@ -134,8 +136,19 @@ module Solargraph
134
136
  source_hash[updater.filename] = source_hash[updater.filename].synchronize(updater)
135
137
  end
136
138
 
139
+ # @return [String]
140
+ def command_path
141
+ server['commandPath'] || 'solargraph'
142
+ end
143
+
137
144
  private
138
145
 
146
+ # The language server configuration (or an empty hash if the workspace was
147
+ # not initialized from a server).
148
+ #
149
+ # @return [Hash]
150
+ attr_reader :server
151
+
139
152
  # @return [Hash{String => Solargraph::Source}]
140
153
  def source_hash
141
154
  @source_hash ||= {}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.53.1
4
+ version: 0.53.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-26 00:00:00.000000000 Z
11
+ date: 2025-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backport
@@ -558,7 +558,6 @@ files:
558
558
  - lib/solargraph/rbs_map/conversions.rb
559
559
  - lib/solargraph/rbs_map/core_fills.rb
560
560
  - lib/solargraph/rbs_map/core_map.rb
561
- - lib/solargraph/rbs_map/core_signs.rb
562
561
  - lib/solargraph/rbs_map/stdlib_map.rb
563
562
  - lib/solargraph/server_methods.rb
564
563
  - lib/solargraph/shell.rb
@@ -1,35 +0,0 @@
1
- module Solargraph
2
- class RbsMap
3
- module CoreSigns
4
- Override = Pin::Reference::Override
5
-
6
- class Stub
7
- attr_reader :parameters
8
-
9
- attr_reader :return_type
10
-
11
- # @param parameters [Array<Hash>]
12
- # @param return_type [String]
13
- def initialize parameters, return_type
14
- @parameters = parameters
15
- @return_type = return_type
16
- end
17
- end
18
-
19
- SIGNATURE_MAP = {
20
- 'Object#class' => [
21
- Stub.new(
22
- [],
23
- 'Class<self>'
24
- )
25
- ]
26
- }
27
-
28
- # @param path [String]
29
- # @return [Array<Stub>]
30
- def self.sign path
31
- SIGNATURE_MAP[path]
32
- end
33
- end
34
- end
35
- end