solargraph 0.54.1 → 0.56.0

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.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +2 -0
  3. data/.github/workflows/typecheck.yml +3 -1
  4. data/.gitignore +2 -0
  5. data/CHANGELOG.md +70 -0
  6. data/README.md +13 -3
  7. data/lib/solargraph/api_map/cache.rb +10 -1
  8. data/lib/solargraph/api_map/index.rb +175 -0
  9. data/lib/solargraph/api_map/store.rb +79 -126
  10. data/lib/solargraph/api_map.rb +247 -93
  11. data/lib/solargraph/bench.rb +17 -1
  12. data/lib/solargraph/complex_type/type_methods.rb +13 -1
  13. data/lib/solargraph/complex_type/unique_type.rb +118 -9
  14. data/lib/solargraph/complex_type.rb +48 -18
  15. data/lib/solargraph/convention/base.rb +3 -3
  16. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +60 -0
  17. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
  18. data/lib/solargraph/convention/struct_definition.rb +101 -0
  19. data/lib/solargraph/convention.rb +5 -3
  20. data/lib/solargraph/doc_map.rb +274 -56
  21. data/lib/solargraph/equality.rb +33 -0
  22. data/lib/solargraph/gem_pins.rb +53 -37
  23. data/lib/solargraph/language_server/host/message_worker.rb +31 -11
  24. data/lib/solargraph/language_server/host.rb +24 -13
  25. data/lib/solargraph/language_server/message/base.rb +19 -12
  26. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  27. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  28. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  29. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  30. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  31. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
  32. data/lib/solargraph/library.rb +13 -11
  33. data/lib/solargraph/location.rb +28 -0
  34. data/lib/solargraph/logging.rb +1 -0
  35. data/lib/solargraph/parser/comment_ripper.rb +12 -6
  36. data/lib/solargraph/parser/flow_sensitive_typing.rb +227 -0
  37. data/lib/solargraph/parser/node_methods.rb +15 -1
  38. data/lib/solargraph/parser/node_processor.rb +3 -1
  39. data/lib/solargraph/parser/parser_gem/class_methods.rb +16 -14
  40. data/lib/solargraph/parser/parser_gem/node_chainer.rb +17 -23
  41. data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -3
  42. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  43. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  44. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  45. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
  46. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +23 -2
  47. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  48. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  49. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  50. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  51. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
  52. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  53. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +4 -3
  54. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +29 -6
  55. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +41 -0
  56. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  57. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  58. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
  59. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +2 -1
  60. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  61. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  62. data/lib/solargraph/parser/parser_gem/node_processors.rb +10 -0
  63. data/lib/solargraph/parser/region.rb +1 -1
  64. data/lib/solargraph/parser.rb +1 -0
  65. data/lib/solargraph/pin/base.rb +326 -43
  66. data/lib/solargraph/pin/base_variable.rb +18 -10
  67. data/lib/solargraph/pin/block.rb +3 -3
  68. data/lib/solargraph/pin/breakable.rb +9 -0
  69. data/lib/solargraph/pin/callable.rb +77 -6
  70. data/lib/solargraph/pin/closure.rb +18 -1
  71. data/lib/solargraph/pin/common.rb +5 -0
  72. data/lib/solargraph/pin/delegated_method.rb +20 -1
  73. data/lib/solargraph/pin/documenting.rb +16 -0
  74. data/lib/solargraph/pin/keyword.rb +7 -2
  75. data/lib/solargraph/pin/local_variable.rb +15 -6
  76. data/lib/solargraph/pin/method.rb +172 -42
  77. data/lib/solargraph/pin/namespace.rb +17 -9
  78. data/lib/solargraph/pin/parameter.rb +61 -11
  79. data/lib/solargraph/pin/proxy_type.rb +12 -6
  80. data/lib/solargraph/pin/reference/override.rb +10 -6
  81. data/lib/solargraph/pin/reference/require.rb +2 -2
  82. data/lib/solargraph/pin/signature.rb +42 -0
  83. data/lib/solargraph/pin/singleton.rb +1 -1
  84. data/lib/solargraph/pin/symbol.rb +3 -2
  85. data/lib/solargraph/pin/until.rb +18 -0
  86. data/lib/solargraph/pin/while.rb +18 -0
  87. data/lib/solargraph/pin.rb +4 -1
  88. data/lib/solargraph/pin_cache.rb +185 -0
  89. data/lib/solargraph/position.rb +16 -0
  90. data/lib/solargraph/range.rb +16 -0
  91. data/lib/solargraph/rbs_map/conversions.rb +199 -66
  92. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  93. data/lib/solargraph/rbs_map/core_map.rb +34 -11
  94. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  95. data/lib/solargraph/rbs_map.rb +74 -16
  96. data/lib/solargraph/shell.rb +19 -18
  97. data/lib/solargraph/source/chain/array.rb +12 -8
  98. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  99. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  100. data/lib/solargraph/source/chain/call.rb +62 -25
  101. data/lib/solargraph/source/chain/constant.rb +1 -1
  102. data/lib/solargraph/source/chain/hash.rb +9 -3
  103. data/lib/solargraph/source/chain/head.rb +1 -1
  104. data/lib/solargraph/source/chain/if.rb +6 -1
  105. data/lib/solargraph/source/chain/link.rb +19 -5
  106. data/lib/solargraph/source/chain/literal.rb +27 -2
  107. data/lib/solargraph/source/chain/or.rb +1 -1
  108. data/lib/solargraph/source/chain/z_super.rb +1 -1
  109. data/lib/solargraph/source/chain.rb +106 -62
  110. data/lib/solargraph/source/cursor.rb +1 -11
  111. data/lib/solargraph/source/source_chainer.rb +2 -2
  112. data/lib/solargraph/source.rb +2 -1
  113. data/lib/solargraph/source_map/clip.rb +4 -2
  114. data/lib/solargraph/source_map/mapper.rb +9 -5
  115. data/lib/solargraph/source_map.rb +0 -17
  116. data/lib/solargraph/type_checker/checks.rb +4 -0
  117. data/lib/solargraph/type_checker.rb +41 -14
  118. data/lib/solargraph/version.rb +1 -1
  119. data/lib/solargraph/views/_method.erb +10 -10
  120. data/lib/solargraph/views/_namespace.erb +3 -3
  121. data/lib/solargraph/views/document.erb +10 -10
  122. data/lib/solargraph/workspace/config.rb +7 -3
  123. data/lib/solargraph/workspace.rb +16 -6
  124. data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -2
  125. data/lib/solargraph/yard_map/mapper/to_method.rb +55 -15
  126. data/lib/solargraph/yard_map/mapper/to_namespace.rb +5 -2
  127. data/lib/solargraph/yard_map/mapper.rb +5 -3
  128. data/lib/solargraph/yard_map/to_method.rb +4 -2
  129. data/lib/solargraph/yardoc.rb +6 -9
  130. data/lib/solargraph.rb +20 -1
  131. data/rbs/fills/tuple.rbs +150 -0
  132. data/rbs_collection.yaml +19 -0
  133. data/solargraph.gemspec +6 -5
  134. metadata +56 -29
  135. data/lib/solargraph/cache.rb +0 -77
@@ -3,20 +3,39 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class Parameter < LocalVariable
6
- # @return [Symbol]
6
+ # @return [::Symbol]
7
7
  attr_reader :decl
8
8
 
9
9
  # @return [String]
10
10
  attr_reader :asgn_code
11
11
 
12
+ # allow this to be set to the method after the method itself has
13
+ # been created
14
+ attr_writer :closure
15
+
12
16
  # @param decl [::Symbol] :arg, :optarg, :kwarg, :kwoptarg, :restarg, :kwrestarg, :block, :blockarg
13
17
  # @param asgn_code [String, nil]
14
- # @param return_type [ComplexType, nil]
15
- def initialize decl: :arg, asgn_code: nil, return_type: nil, **splat
18
+ def initialize decl: :arg, asgn_code: nil, **splat
16
19
  super(**splat)
17
20
  @asgn_code = asgn_code
18
21
  @decl = decl
19
- @return_type = return_type
22
+ end
23
+
24
+ def type_location
25
+ super || closure&.type_location
26
+ end
27
+
28
+ def location
29
+ super || closure&.type_location
30
+ end
31
+
32
+ def combine_with(other, attrs={})
33
+ new_attrs = {
34
+ decl: assert_same(other, :decl),
35
+ presence: choose(other, :presence),
36
+ asgn_code: choose(other, :asgn_code),
37
+ }.merge(attrs)
38
+ super(other, new_attrs)
20
39
  end
21
40
 
22
41
  def keyword?
@@ -27,6 +46,32 @@ module Solargraph
27
46
  decl == :kwrestarg || (assignment && [:HASH, :hash].include?(assignment.type))
28
47
  end
29
48
 
49
+ def needs_consistent_name?
50
+ keyword?
51
+ end
52
+
53
+ # @return [String]
54
+ def arity_decl
55
+ name = (self.name || '(anon)')
56
+ type = (return_type&.to_rbs || 'untyped')
57
+ case decl
58
+ when :arg
59
+ ""
60
+ when :optarg
61
+ "?"
62
+ when :kwarg
63
+ "#{name}:"
64
+ when :kwoptarg
65
+ "?#{name}:"
66
+ when :restarg
67
+ "*"
68
+ when :kwrestarg
69
+ "**"
70
+ else
71
+ "(unknown decl: #{decl})"
72
+ end
73
+ end
74
+
30
75
  def arg?
31
76
  decl == :arg
32
77
  end
@@ -115,17 +160,21 @@ module Solargraph
115
160
  closure.is_a?(Pin::Block) ? typify_block_param(api_map) : typify_method_param(api_map)
116
161
  end
117
162
 
163
+ # @param atype [ComplexType]
164
+ # @param api_map [ApiMap]
165
+ def compatible_arg?(atype, api_map)
166
+ # make sure we get types from up the method
167
+ # inheritance chain if we don't have them on this pin
168
+ ptype = typify api_map
169
+ ptype.undefined? || ptype.can_assign?(api_map, atype) || ptype.generic?
170
+ end
171
+
118
172
  def documentation
119
173
  tag = param_tag
120
174
  return '' if tag.nil? || tag.text.nil?
121
175
  tag.text
122
176
  end
123
177
 
124
- def try_merge! pin
125
- return false unless super && closure == pin.closure
126
- true
127
- end
128
-
129
178
  private
130
179
 
131
180
  # @return [YARD::Tags::Tag, nil]
@@ -140,8 +189,9 @@ module Solargraph
140
189
  # @param api_map [ApiMap]
141
190
  # @return [ComplexType]
142
191
  def typify_block_param api_map
143
- if closure.is_a?(Pin::Block) && closure.receiver
144
- return closure.typify_parameters(api_map)[index]
192
+ block_pin = closure
193
+ if block_pin.is_a?(Pin::Block) && block_pin.receiver
194
+ return block_pin.typify_parameters(api_map)[index]
145
195
  end
146
196
  ComplexType::UNDEFINED
147
197
  end
@@ -4,24 +4,30 @@ module Solargraph
4
4
  module Pin
5
5
  class ProxyType < Base
6
6
  # @param return_type [ComplexType]
7
- def initialize return_type: ComplexType::UNDEFINED, **splat
7
+ def initialize return_type: ComplexType::UNDEFINED, binder: nil, **splat
8
8
  super(**splat)
9
9
  @return_type = return_type
10
+ @binder = binder if binder
10
11
  end
11
12
 
12
13
  def context
13
14
  @return_type
14
15
  end
15
16
 
16
- # @param return_type [ComplexType]
17
+ # @param context [ComplexType, ComplexType::UniqueType] Used as context for this pin
18
+ # @param closure [Pin::Namespace, nil] Used as the closure for this pin
19
+ # @param binder [ComplexType, ComplexType::UniqueType, nil]
17
20
  # @return [ProxyType]
18
- def self.anonymous return_type
19
- parts = return_type.namespace.split('::')
20
- namespace = parts[0..-2].join('::').to_s
21
+ def self.anonymous context, closure: nil, binder: nil, **kwargs
22
+ unless closure
23
+ parts = context.namespace.split('::')
24
+ namespace = parts[0..-2].join('::').to_s
25
+ closure = Solargraph::Pin::Namespace.new(name: namespace, source: :proxy_type)
26
+ end
21
27
  # name = parts.last.to_s
22
28
  # ProxyType.new(nil, namespace, name, return_type)
23
29
  ProxyType.new(
24
- closure: Solargraph::Pin::Namespace.new(name: namespace), return_type: return_type
30
+ closure: closure, return_type: context, binder: binder || context, **kwargs
25
31
  )
26
32
  end
27
33
  end
@@ -10,18 +10,22 @@ module Solargraph
10
10
  # @return [::Array<Symbol>]
11
11
  attr_reader :delete
12
12
 
13
- def initialize location, name, tags, delete = []
14
- super(location: location, name: name)
13
+ def closure
14
+ nil
15
+ end
16
+
17
+ def initialize location, name, tags, delete = [], **splat
18
+ super(location: location, name: name, **splat)
15
19
  @tags = tags
16
20
  @delete = delete
17
21
  end
18
22
 
19
- def self.method_return name, *tags, delete: []
20
- new(nil, name, [YARD::Tags::Tag.new('return', nil, tags)], delete)
23
+ def self.method_return name, *tags, delete: [], **splat
24
+ new(nil, name, [YARD::Tags::Tag.new('return', nil, tags)], delete, **splat)
21
25
  end
22
26
 
23
- def self.from_comment name, comment
24
- new(nil, name, Solargraph::Source.parse_docstring(comment).to_docstring.tags)
27
+ def self.from_comment name, comment, **splat
28
+ new(nil, name, Solargraph::Source.parse_docstring(comment).to_docstring.tags, **splat)
25
29
  end
26
30
  end
27
31
  end
@@ -4,9 +4,9 @@ module Solargraph
4
4
  module Pin
5
5
  class Reference
6
6
  class Require < Reference
7
- def initialize location, name
7
+ def initialize location, name, **splat
8
8
  # super(location, '', name)
9
- super(location: location, name: name)
9
+ super(location: location, name: name, closure: Pin::ROOT_PIN, **splat)
10
10
  end
11
11
  end
12
12
  end
@@ -1,6 +1,10 @@
1
1
  module Solargraph
2
2
  module Pin
3
3
  class Signature < Callable
4
+ # allow signature to be created before method pin, then set this
5
+ # to the method pin
6
+ attr_writer :closure
7
+
4
8
  def initialize **splat
5
9
  super(**splat)
6
10
  end
@@ -12,6 +16,44 @@ module Solargraph
12
16
  def identity
13
17
  @identity ||= "signature#{object_id}"
14
18
  end
19
+
20
+ attr_writer :closure
21
+
22
+ def dodgy_return_type_source?
23
+ super || closure&.dodgy_return_type_source?
24
+ end
25
+
26
+ def type_location
27
+ super || closure&.type_location
28
+ end
29
+
30
+ def location
31
+ super || closure&.location
32
+ end
33
+
34
+ def typify api_map
35
+ if return_type.defined?
36
+ qualified = return_type.qualify(api_map, closure.namespace)
37
+ logger.debug { "Signature#typify(self=#{self}) => #{qualified.rooted_tags.inspect}" }
38
+ return qualified
39
+ end
40
+ return ComplexType::UNDEFINED if closure.nil?
41
+ return ComplexType::UNDEFINED unless closure.is_a?(Pin::Method)
42
+ method_stack = closure.rest_of_stack api_map
43
+ logger.debug { "Signature#typify(self=#{self}) - method_stack: #{method_stack}" }
44
+ method_stack.each do |pin|
45
+ sig = pin.signatures.find { |s| s.arity == self.arity }
46
+ next unless sig
47
+ unless sig.return_type.undefined?
48
+ qualified = sig.return_type.qualify(api_map, closure.namespace)
49
+ logger.debug { "Signature#typify(self=#{self}) => #{qualified.rooted_tags.inspect}" }
50
+ return qualified
51
+ end
52
+ end
53
+ out = super
54
+ logger.debug { "Signature#typify(self=#{self}) => #{out}" }
55
+ out
56
+ end
15
57
  end
16
58
  end
17
59
  end
@@ -3,7 +3,7 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class Singleton < Closure
6
- def initialize name: '', location: nil, closure: nil
6
+ def initialize name: '', location: nil, closure: nil, **splat
7
7
  super
8
8
  end
9
9
  end
@@ -5,8 +5,9 @@ module Solargraph
5
5
  class Symbol < Base
6
6
  # @param location [Solargraph::Location]
7
7
  # @param name [String]
8
- def initialize location, name
9
- super(location: location, name: name)
8
+ def initialize(location, name, **kwargs)
9
+ # @sg-ignore "Unrecognized keyword argument kwargs to Solargraph::Pin::Base#initialize"
10
+ super(location: location, name: name, **kwargs)
10
11
  # @name = name
11
12
  # @location = location
12
13
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class Until < Base
6
+ include Breakable
7
+
8
+ # @param receiver [Parser::AST::Node, nil]
9
+ # @param node [Parser::AST::Node, nil]
10
+ # @param context [ComplexType, nil]
11
+ # @param args [::Array<Parameter>]
12
+ def initialize node: nil, **splat
13
+ super(**splat)
14
+ @node = node
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class While < Base
6
+ include Breakable
7
+
8
+ # @param receiver [Parser::AST::Node, nil]
9
+ # @param node [Parser::AST::Node, nil]
10
+ # @param context [ComplexType, nil]
11
+ # @param args [::Array<Parameter>]
12
+ def initialize node: nil, **splat
13
+ super(**splat)
14
+ @node = node
15
+ end
16
+ end
17
+ end
18
+ end
@@ -34,8 +34,11 @@ module Solargraph
34
34
  autoload :Singleton, 'solargraph/pin/singleton'
35
35
  autoload :KeywordParam, 'solargraph/pin/keyword_param'
36
36
  autoload :Search, 'solargraph/pin/search'
37
+ autoload :Breakable, 'solargraph/pin/breakable'
38
+ autoload :Until, 'solargraph/pin/until'
39
+ autoload :While, 'solargraph/pin/while'
37
40
  autoload :Callable, 'solargraph/pin/callable'
38
41
 
39
- ROOT_PIN = Pin::Namespace.new(type: :class, name: '', closure: nil)
42
+ ROOT_PIN = Pin::Namespace.new(type: :class, name: '', closure: nil, source: :pin_rb)
40
43
  end
41
44
  end
@@ -0,0 +1,185 @@
1
+ require 'fileutils'
2
+ require 'rbs'
3
+
4
+ module Solargraph
5
+ module PinCache
6
+ class << self
7
+ include Logging
8
+
9
+ # The base directory where cached YARD documentation and serialized pins are serialized
10
+ #
11
+ # @return [String]
12
+ def base_dir
13
+ # The directory is not stored in a variable so it can be overridden
14
+ # in specs.
15
+ ENV['SOLARGRAPH_CACHE'] ||
16
+ (ENV['XDG_CACHE_HOME'] ? File.join(ENV['XDG_CACHE_HOME'], 'solargraph') : nil) ||
17
+ File.join(Dir.home, '.cache', 'solargraph')
18
+ end
19
+
20
+ # The working directory for the current Ruby, RBS, and Solargraph versions.
21
+ #
22
+ # @return [String]
23
+ def work_dir
24
+ # The directory is not stored in a variable so it can be overridden
25
+ # in specs.
26
+ File.join(base_dir, "ruby-#{RUBY_VERSION}", "rbs-#{RBS::VERSION}", "solargraph-#{Solargraph::VERSION}")
27
+ end
28
+
29
+ def yardoc_path gemspec
30
+ File.join(base_dir, "yard-#{YARD::VERSION}", "#{gemspec.name}-#{gemspec.version}.yardoc")
31
+ end
32
+
33
+ def stdlib_path
34
+ File.join(work_dir, 'stdlib')
35
+ end
36
+
37
+ def stdlib_require_path require
38
+ File.join(stdlib_path, "#{require}.ser")
39
+ end
40
+
41
+ def deserialize_stdlib_require require
42
+ load(stdlib_require_path(require))
43
+ end
44
+
45
+ def serialize_stdlib_require require, pins
46
+ save(stdlib_require_path(require), pins)
47
+ end
48
+
49
+ def core_path
50
+ File.join(work_dir, 'core.ser')
51
+ end
52
+
53
+ def deserialize_core
54
+ load(core_path)
55
+ end
56
+
57
+ def serialize_core pins
58
+ save(core_path, pins)
59
+ end
60
+
61
+ def yard_gem_path gemspec
62
+ File.join(work_dir, 'yard', "#{gemspec.name}-#{gemspec.version}.ser")
63
+ end
64
+
65
+ def deserialize_yard_gem(gemspec)
66
+ load(yard_gem_path(gemspec))
67
+ end
68
+
69
+ def serialize_yard_gem(gemspec, pins)
70
+ save(yard_gem_path(gemspec), pins)
71
+ end
72
+
73
+ def has_yard?(gemspec)
74
+ exist?(yard_gem_path(gemspec))
75
+ end
76
+
77
+ def rbs_collection_path(gemspec, hash)
78
+ File.join(work_dir, 'rbs', "#{gemspec.name}-#{gemspec.version}-#{hash || 0}.ser")
79
+ end
80
+
81
+ def rbs_collection_path_prefix(gemspec)
82
+ File.join(work_dir, 'rbs', "#{gemspec.name}-#{gemspec.version}-")
83
+ end
84
+
85
+ def deserialize_rbs_collection_gem(gemspec, hash)
86
+ load(rbs_collection_path(gemspec, hash))
87
+ end
88
+
89
+ def serialize_rbs_collection_gem(gemspec, hash, pins)
90
+ save(rbs_collection_path(gemspec, hash), pins)
91
+ end
92
+
93
+ def combined_path(gemspec, hash)
94
+ File.join(work_dir, 'combined', "#{gemspec.name}-#{gemspec.version}-#{hash || 0}.ser")
95
+ end
96
+
97
+ def combined_path_prefix(gemspec)
98
+ File.join(work_dir, 'combined', "#{gemspec.name}-#{gemspec.version}-")
99
+ end
100
+
101
+ def serialize_combined_gem(gemspec, hash, pins)
102
+ save(combined_path(gemspec, hash), pins)
103
+ end
104
+
105
+ def deserialize_combined_gem gemspec, hash
106
+ load(combined_path(gemspec, hash))
107
+ end
108
+
109
+ def has_rbs_collection?(gemspec, hash)
110
+ exist?(rbs_collection_path(gemspec, hash))
111
+ end
112
+
113
+ def uncache_core
114
+ uncache(core_path)
115
+ end
116
+
117
+ def uncache_stdlib
118
+ uncache(stdlib_path)
119
+ end
120
+
121
+ def uncache_gem(gemspec, out: nil)
122
+ uncache(yardoc_path(gemspec), out: out)
123
+ uncache_by_prefix(rbs_collection_path_prefix(gemspec), out: out)
124
+ uncache(yard_gem_path(gemspec), out: out)
125
+ uncache_by_prefix(combined_path_prefix(gemspec), out: out)
126
+ end
127
+
128
+ # @return [void]
129
+ def clear
130
+ FileUtils.rm_rf base_dir, secure: true
131
+ end
132
+
133
+ private
134
+
135
+ # @param file [String]
136
+ # @return [Array<Solargraph::Pin::Base>, nil]
137
+ def load file
138
+ return nil unless File.file?(file)
139
+ Marshal.load(File.read(file, mode: 'rb'))
140
+ rescue StandardError => e
141
+ Solargraph.logger.warn "Failed to load cached file #{file}: [#{e.class}] #{e.message}"
142
+ FileUtils.rm_f file
143
+ nil
144
+ end
145
+
146
+ def exist? *path
147
+ File.file? join(*path)
148
+ end
149
+
150
+ # @param path [Array<String>]
151
+ # @param pins [Array<Pin::Base>]
152
+ # @return [void]
153
+ def save file, pins
154
+ base = File.dirname(file)
155
+ FileUtils.mkdir_p base unless File.directory?(base)
156
+ ser = Marshal.dump(pins)
157
+ File.write file, ser, mode: 'wb'
158
+ logger.debug { "Cache#save: Saved #{pins.length} pins to #{file}" }
159
+ end
160
+
161
+ # @return [void]
162
+ # @param path_segments [Array<String>]
163
+ def uncache *path_segments, out: nil
164
+ path = File.join(*path_segments)
165
+ if File.exist?(path)
166
+ FileUtils.rm_rf path, secure: true
167
+ out.puts "Clearing pin cache in #{path}" unless out.nil?
168
+ end
169
+ end
170
+
171
+ # @return [void]
172
+ # @param path_segments [Array<String>]
173
+ def uncache_by_prefix *path_segments, out: nil
174
+ path = File.join(*path_segments)
175
+ glob = "#{path}*"
176
+ out.puts "Clearing pin cache in #{glob}" unless out.nil?
177
+ Dir.glob(glob).each do |file|
178
+ next unless File.file?(file)
179
+ FileUtils.rm_rf file, secure: true
180
+ out.puts "Clearing pin cache in #{file}" unless out.nil?
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -4,6 +4,8 @@ module Solargraph
4
4
  # The zero-based line and column numbers of a position in a string.
5
5
  #
6
6
  class Position
7
+ include Equality
8
+
7
9
  # @return [Integer]
8
10
  attr_reader :line
9
11
 
@@ -19,6 +21,20 @@ module Solargraph
19
21
  @character = character
20
22
  end
21
23
 
24
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
25
+ protected def equality_fields
26
+ [line, character]
27
+ end
28
+
29
+ def <=>(other)
30
+ return nil unless other.is_a?(Position)
31
+ if line == other.line
32
+ character <=> other.character
33
+ else
34
+ line <=> other.line
35
+ end
36
+ end
37
+
22
38
  # Get a hash of the position. This representation is suitable for use in
23
39
  # the language server protocol.
24
40
  #
@@ -4,6 +4,8 @@ module Solargraph
4
4
  # A pair of Positions that compose a section of text in code.
5
5
  #
6
6
  class Range
7
+ include Equality
8
+
7
9
  # @return [Position]
8
10
  attr_reader :start
9
11
 
@@ -17,6 +19,20 @@ module Solargraph
17
19
  @ending = ending
18
20
  end
19
21
 
22
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
23
+ protected def equality_fields
24
+ [start, ending]
25
+ end
26
+
27
+ def <=>(other)
28
+ return nil unless other.is_a?(Range)
29
+ if start == other.start
30
+ ending <=> other.ending
31
+ else
32
+ start <=> other.start
33
+ end
34
+ end
35
+
20
36
  # Get a hash of the range. This representation is suitable for use in
21
37
  # the language server protocol.
22
38
  #