solargraph 0.47.2 → 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.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/plugins.yml +40 -0
  4. data/.github/workflows/rspec.yml +4 -8
  5. data/.github/workflows/typecheck.yml +34 -0
  6. data/.yardopts +2 -2
  7. data/CHANGELOG.md +137 -3
  8. data/LICENSE +1 -1
  9. data/README.md +19 -16
  10. data/SPONSORS.md +2 -9
  11. data/lib/solargraph/api_map/cache.rb +60 -20
  12. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  13. data/lib/solargraph/api_map/store.rb +60 -12
  14. data/lib/solargraph/api_map.rb +171 -99
  15. data/lib/solargraph/bench.rb +3 -2
  16. data/lib/solargraph/cache.rb +77 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +61 -12
  18. data/lib/solargraph/complex_type/unique_type.rb +193 -16
  19. data/lib/solargraph/complex_type.rb +113 -10
  20. data/lib/solargraph/convention/rakefile.rb +17 -0
  21. data/lib/solargraph/convention.rb +2 -3
  22. data/lib/solargraph/converters/dd.rb +5 -0
  23. data/lib/solargraph/converters/dl.rb +3 -0
  24. data/lib/solargraph/converters/dt.rb +3 -0
  25. data/lib/solargraph/diagnostics/rubocop.rb +23 -8
  26. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  27. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  28. data/lib/solargraph/diagnostics.rb +2 -2
  29. data/lib/solargraph/doc_map.rb +171 -0
  30. data/lib/solargraph/gem_pins.rb +64 -0
  31. data/lib/solargraph/language_server/host/cataloger.rb +2 -1
  32. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  33. data/lib/solargraph/language_server/host/dispatch.rb +15 -5
  34. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  35. data/lib/solargraph/language_server/host/sources.rb +7 -4
  36. data/lib/solargraph/language_server/host.rb +50 -26
  37. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  38. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  39. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  40. data/lib/solargraph/language_server/message/initialize.rb +13 -0
  41. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  42. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  43. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  44. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  46. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  47. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  48. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  49. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  50. data/lib/solargraph/language_server/message.rb +1 -0
  51. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  52. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  53. data/lib/solargraph/library.rb +124 -37
  54. data/lib/solargraph/location.rb +1 -0
  55. data/lib/solargraph/page.rb +6 -0
  56. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  57. data/lib/solargraph/parser/node_methods.rb +47 -7
  58. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  59. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  60. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  62. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  64. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  65. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  69. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  71. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  72. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  77. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
  78. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  79. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  81. data/lib/solargraph/parser/parser_gem.rb +12 -0
  82. data/lib/solargraph/parser/region.rb +1 -1
  83. data/lib/solargraph/parser/snippet.rb +2 -0
  84. data/lib/solargraph/parser.rb +9 -10
  85. data/lib/solargraph/pin/base.rb +69 -11
  86. data/lib/solargraph/pin/base_variable.rb +8 -4
  87. data/lib/solargraph/pin/block.rb +21 -28
  88. data/lib/solargraph/pin/closure.rb +17 -2
  89. data/lib/solargraph/pin/common.rb +7 -3
  90. data/lib/solargraph/pin/conversions.rb +34 -8
  91. data/lib/solargraph/pin/delegated_method.rb +97 -0
  92. data/lib/solargraph/pin/documenting.rb +25 -34
  93. data/lib/solargraph/pin/instance_variable.rb +4 -0
  94. data/lib/solargraph/pin/local_variable.rb +13 -1
  95. data/lib/solargraph/pin/method.rb +270 -16
  96. data/lib/solargraph/pin/namespace.rb +17 -1
  97. data/lib/solargraph/pin/parameter.rb +52 -17
  98. data/lib/solargraph/pin/reference/override.rb +2 -2
  99. data/lib/solargraph/pin/reference.rb +8 -0
  100. data/lib/solargraph/pin/search.rb +4 -4
  101. data/lib/solargraph/pin/signature.rb +143 -0
  102. data/lib/solargraph/pin.rb +2 -1
  103. data/lib/solargraph/range.rb +4 -6
  104. data/lib/solargraph/rbs_map/conversions.rb +601 -0
  105. data/lib/solargraph/rbs_map/core_fills.rb +47 -0
  106. data/lib/solargraph/rbs_map/core_map.rb +28 -0
  107. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
  108. data/lib/solargraph/rbs_map.rb +84 -0
  109. data/lib/solargraph/shell.rb +69 -48
  110. data/lib/solargraph/source/chain/array.rb +32 -0
  111. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  112. data/lib/solargraph/source/chain/call.rb +125 -61
  113. data/lib/solargraph/source/chain/constant.rb +15 -1
  114. data/lib/solargraph/source/chain/if.rb +23 -0
  115. data/lib/solargraph/source/chain/link.rb +8 -2
  116. data/lib/solargraph/source/chain/or.rb +1 -1
  117. data/lib/solargraph/source/chain/z_super.rb +3 -3
  118. data/lib/solargraph/source/chain.rb +44 -14
  119. data/lib/solargraph/source/change.rb +3 -0
  120. data/lib/solargraph/source/cursor.rb +2 -0
  121. data/lib/solargraph/source/source_chainer.rb +8 -5
  122. data/lib/solargraph/source.rb +18 -19
  123. data/lib/solargraph/source_map/clip.rb +30 -23
  124. data/lib/solargraph/source_map/mapper.rb +20 -5
  125. data/lib/solargraph/source_map.rb +28 -13
  126. data/lib/solargraph/type_checker/checks.rb +10 -2
  127. data/lib/solargraph/type_checker.rb +201 -98
  128. data/lib/solargraph/version.rb +1 -1
  129. data/lib/solargraph/views/environment.erb +2 -2
  130. data/lib/solargraph/workspace/config.rb +14 -11
  131. data/lib/solargraph/workspace.rb +28 -17
  132. data/lib/solargraph/yard_map/cache.rb +6 -0
  133. data/lib/solargraph/yard_map/helpers.rb +1 -1
  134. data/lib/solargraph/yard_map/mapper/to_method.rb +18 -5
  135. data/lib/solargraph/yard_map/mapper.rb +1 -1
  136. data/lib/solargraph/yard_map/to_method.rb +11 -4
  137. data/lib/solargraph/yard_map.rb +1 -443
  138. data/lib/solargraph/yard_tags.rb +20 -0
  139. data/lib/solargraph/yardoc.rb +52 -0
  140. data/lib/solargraph.rb +8 -6
  141. data/solargraph.gemspec +19 -8
  142. metadata +162 -98
  143. data/.travis.yml +0 -19
  144. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  145. data/lib/solargraph/compat.rb +0 -37
  146. data/lib/solargraph/convention/rspec.rb +0 -30
  147. data/lib/solargraph/documentor.rb +0 -76
  148. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  149. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  150. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  151. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  152. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
  153. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
  154. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  155. data/lib/solargraph/parser/legacy.rb +0 -12
  156. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
  157. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  158. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  159. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  160. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  161. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
  162. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  163. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
  164. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  165. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  166. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  167. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  168. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  169. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  170. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  171. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  172. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  173. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
  174. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  175. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
  176. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
  177. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  178. data/lib/solargraph/parser/rubyvm.rb +0 -40
  179. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  180. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  181. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  182. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  183. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  184. data/lib/yard-solargraph.rb +0 -33
  185. data/yardoc/2.2.2.tar.gz +0 -0
@@ -11,6 +11,7 @@ module Solargraph
11
11
 
12
12
  # Conversion of RuboCop severity names to LSP constants
13
13
  SEVERITIES = {
14
+ 'info' => Severities::HINT,
14
15
  'refactor' => Severities::HINT,
15
16
  'convention' => Severities::INFORMATION,
16
17
  'warning' => Severities::WARNING,
@@ -22,16 +23,20 @@ module Solargraph
22
23
  # @param _api_map [Solargraph::ApiMap]
23
24
  # @return [Array<Hash>]
24
25
  def diagnose source, _api_map
26
+ @source = source
25
27
  require_rubocop(rubocop_version)
26
28
  options, paths = generate_options(source.filename, source.code)
27
29
  store = RuboCop::ConfigStore.new
28
30
  runner = RuboCop::Runner.new(options, store)
29
31
  result = redirect_stdout{ runner.run(paths) }
32
+
33
+ return [] if result.empty?
34
+
30
35
  make_array JSON.parse(result)
31
36
  rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
32
37
  raise DiagnosticsError, "Error in RuboCop configuration: #{e.message}"
33
- rescue JSON::ParserError
34
- raise DiagnosticsError, 'RuboCop returned invalid data'
38
+ rescue JSON::ParserError => e
39
+ raise DiagnosticsError, "RuboCop returned invalid data: #{e.message}"
35
40
  end
36
41
 
37
42
  private
@@ -43,7 +48,7 @@ module Solargraph
43
48
  args.find { |a| a =~ /version=/ }.to_s.split('=').last
44
49
  end
45
50
 
46
- # @param resp [Hash]
51
+ # @param resp [Hash{String => Array<Hash{String => Array<Hash{String => undefined}>}>}]
47
52
  # @return [Array<Hash>]
48
53
  def make_array resp
49
54
  diagnostics = []
@@ -57,8 +62,8 @@ module Solargraph
57
62
 
58
63
  # Convert a RuboCop offense to an LSP diagnostic
59
64
  #
60
- # @param off [Hash] Offense received from Rubocop
61
- # @return [Hash] LSP diagnostic
65
+ # @param off [Hash{String => unknown}] Offense received from Rubocop
66
+ # @return [Hash{Symbol => Hash, String, Integer}] LSP diagnostic
62
67
  def offense_to_diagnostic off
63
68
  {
64
69
  range: offense_range(off).to_hash,
@@ -76,20 +81,30 @@ module Solargraph
76
81
  Range.new(offense_start_position(off), offense_ending_position(off))
77
82
  end
78
83
 
79
- # @param off [Hash]
84
+ # @param off [Hash{String => Hash{String => Integer}}]
80
85
  # @return [Position]
81
86
  def offense_start_position off
82
87
  Position.new(off['location']['start_line'] - 1, off['location']['start_column'] - 1)
83
88
  end
84
89
 
85
- # @param off [Hash]
90
+ # @param off [Hash{String => Hash{String => Integer}}]
86
91
  # @return [Position]
87
92
  def offense_ending_position off
88
93
  if off['location']['start_line'] != off['location']['last_line']
89
94
  Position.new(off['location']['start_line'], 0)
90
95
  else
96
+ start_line = off['location']['start_line'] - 1
97
+ # @type [Integer]
98
+ last_column = off['location']['last_column']
99
+ line = @source.code.lines[start_line]
100
+ col_off = if line.nil? || line.empty?
101
+ 1
102
+ else
103
+ 0
104
+ end
105
+
91
106
  Position.new(
92
- off['location']['start_line'] - 1, off['location']['last_column'] - 1
107
+ start_line, last_column - col_off
93
108
  )
94
109
  end
95
110
  end
@@ -10,13 +10,16 @@ module Solargraph
10
10
  # Requires a specific version of rubocop, or the latest installed version
11
11
  # if _version_ is `nil`.
12
12
  #
13
- # @param version [String]
13
+ # @param version [String, nil]
14
14
  # @raise [InvalidRubocopVersionError] if _version_ is not installed
15
+ # @return [void]
15
16
  def require_rubocop(version = nil)
16
17
  begin
17
18
  gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
18
19
  gem_lib_path = File.join(gem_path, 'lib')
19
20
  $LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
21
+ # @todo Gem::MissingSpecVersionError is undocumented for some reason
22
+ # @sg-ignore
20
23
  rescue Gem::MissingSpecVersionError => e
21
24
  raise InvalidRubocopVersionError,
22
25
  "could not find '#{e.name}' (#{e.requirement}) - "\
@@ -6,6 +6,7 @@ module Solargraph
6
6
  # parameters, and invalid param tags.
7
7
  #
8
8
  class TypeCheck < Base
9
+ # @return [Array<Hash>]
9
10
  def diagnose source, api_map
10
11
  # return [] unless args.include?('always') || api_map.workspaced?(source.filename)
11
12
  severity = Diagnostics::Severities::ERROR
@@ -33,14 +33,14 @@ module Solargraph
33
33
  # Find a reporter by name.
34
34
  #
35
35
  # @param name [String] The name with which the reporter was registered
36
- # @return [Class<Solargraph::Diagnostics::Base>]
36
+ # @return [Class<Solargraph::Diagnostics::Base>, nil]
37
37
  def reporter name
38
38
  reporter_hash[name]
39
39
  end
40
40
 
41
41
  private
42
42
 
43
- # @return [Hash]
43
+ # @return [Hash{String => Class<Solargraph::Diagnostics::Base>}]
44
44
  def reporter_hash
45
45
  @reporter_hash ||= {}
46
46
  end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # A collection of pins generated from required gems.
5
+ #
6
+ class DocMap
7
+ # @return [Array<String>]
8
+ attr_reader :requires
9
+
10
+ # @return [Array<Gem::Specification>]
11
+ attr_reader :preferences
12
+
13
+ # @return [Array<Pin::Base>]
14
+ attr_reader :pins
15
+
16
+ # @return [Array<Gem::Specification>]
17
+ attr_reader :uncached_gemspecs
18
+
19
+ # @param requires [Array<String>]
20
+ # @param preferences [Array<Gem::Specification>]
21
+ def initialize(requires, preferences)
22
+ @requires = requires.compact
23
+ @preferences = preferences.compact
24
+ generate
25
+ end
26
+
27
+ # @return [Array<Gem::Specification>]
28
+ def gemspecs
29
+ @gemspecs ||= required_gem_map.values.compact
30
+ end
31
+
32
+ # @return [Array<String>]
33
+ def unresolved_requires
34
+ @unresolved_requires ||= required_gem_map.select { |_, gemspec| gemspec.nil? }.keys
35
+ end
36
+
37
+ # @return [Hash{Gem::Specification => Array[Pin::Base]}]
38
+ def self.gems_in_memory
39
+ @gems_in_memory ||= {}
40
+ end
41
+
42
+ def dependencies
43
+ @dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
44
+ end
45
+
46
+ private
47
+
48
+ # @return [void]
49
+ def generate
50
+ @pins = []
51
+ @uncached_gemspecs = []
52
+ required_gem_map.each do |path, gemspec|
53
+ if gemspec
54
+ try_cache gemspec
55
+ else
56
+ try_stdlib_map path
57
+ end
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] }
70
+ end
71
+
72
+ # @param gemspec [Gem::Specification]
73
+ # @return [void]
74
+ def try_cache gemspec
75
+ return if try_gem_in_memory(gemspec)
76
+ cache_file = File.join('gems', "#{gemspec.name}-#{gemspec.version}.ser")
77
+ if Cache.exist?(cache_file)
78
+ gempins = Cache.load(cache_file)
79
+ self.class.gems_in_memory[gemspec] = gempins
80
+ @pins.concat gempins
81
+ else
82
+ Solargraph.logger.debug "No pin cache for #{gemspec.name} #{gemspec.version}"
83
+ @uncached_gemspecs.push gemspec
84
+ end
85
+ end
86
+
87
+ # @param path [String] require path that might be in the RBS stdlib collection
88
+ # @return [void]
89
+ def try_stdlib_map path
90
+ map = RbsMap::StdlibMap.load(path)
91
+ if map.resolved?
92
+ Solargraph.logger.debug "Loading stdlib pins for #{path}"
93
+ @pins.concat map.pins
94
+ else
95
+ # @todo Temporarily ignoring unresolved `require 'set'`
96
+ Solargraph.logger.warn "Require path #{path} could not be resolved" unless path == 'set'
97
+ end
98
+ end
99
+
100
+ # @param gemspec [Gem::Specification]
101
+ # @return [Boolean]
102
+ def try_gem_in_memory gemspec
103
+ gempins = DocMap.gems_in_memory[gemspec]
104
+ return false unless gempins
105
+ Solargraph.logger.debug "Found #{gemspec.name} #{gemspec.version} in memory"
106
+ @pins.concat gempins
107
+ true
108
+ end
109
+
110
+ # @param path [String]
111
+ # @return [Gem::Specification, nil]
112
+ def resolve_path_to_gemspec path
113
+ return nil if path.empty?
114
+
115
+ gemspec = Gem::Specification.find_by_path(path)
116
+ if gemspec.nil?
117
+ gem_name_guess = path.split('/').first
118
+ begin
119
+ # this can happen when the gem is included via a local path in
120
+ # a Gemfile; Gem doesn't try to index the paths in that case.
121
+ #
122
+ # See if we can make a good guess:
123
+ potential_gemspec = Gem::Specification.find_by_name(gem_name_guess)
124
+ file = "lib/#{path}.rb"
125
+ gemspec = potential_gemspec if potential_gemspec.files.any? { |gemspec_file| file == gemspec_file }
126
+ rescue Gem::MissingSpecError
127
+ Solargraph.logger.debug "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}"
128
+ nil
129
+ end
130
+ end
131
+ gemspec_or_preference gemspec
132
+ end
133
+
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
139
+
140
+ change_gemspec_version gemspec, preference_map[by_path.name].version
141
+ end
142
+
143
+ # @param gemspec [Gem::Specification]
144
+ # @param version [Gem::Version]
145
+ # @return [Gem::Specification]
146
+ def change_gemspec_version gemspec, version
147
+ Gem::Specification.find_by_name(gemspec.name, "= #{version}")
148
+ rescue Gem::MissingSpecError
149
+ Solargraph.logger.info "Gem #{gemspec.name} version #{version} not found. Using #{gemspec.version} instead"
150
+ gemspec
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
170
+ end
171
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+
5
+ module Solargraph
6
+ # A utility for building gem pins from a combination of YARD and RBS
7
+ # documentation.
8
+ #
9
+ module GemPins
10
+ # Build an array of pins from a gem specification. The process starts with
11
+ # YARD, enhances the resulting pins with RBS definitions, and appends RBS
12
+ # pins that don't exist in the YARD mapping.
13
+ #
14
+ # @param gemspec [Gem::Specification]
15
+ # @return [Array<Pin::Base>]
16
+ def self.build(gemspec)
17
+ yard_pins = build_yard_pins(gemspec)
18
+ rbs_map = RbsMap.from_gemspec(gemspec)
19
+ in_yard = Set.new
20
+ combined = yard_pins.map do |yard|
21
+ in_yard.add yard.path
22
+ next yard unless yard.is_a?(Pin::Method)
23
+ rbs = rbs_map.path_pin(yard.path, Pin::Method)
24
+ next yard unless rbs
25
+ # @todo Could not include: attribute and anon_splat
26
+ # @sg-ignore
27
+ yard.class.new(
28
+ location: yard.location,
29
+ closure: yard.closure,
30
+ name: yard.name,
31
+ comments: yard.comments,
32
+ scope: yard.scope,
33
+ parameters: rbs.parameters,
34
+ generics: rbs.generics,
35
+ node: yard.node,
36
+ signatures: yard.signatures,
37
+ return_type: best_return_type(rbs.return_type, yard.return_type)
38
+ )
39
+ end
40
+ in_rbs = rbs_map.pins.reject { |pin| in_yard.include?(pin.path) }
41
+ combined + in_rbs
42
+ end
43
+
44
+ class << self
45
+ private
46
+
47
+ # @param gemspec [Gem::Specification]
48
+ # @return [Array<Pin::Base>]
49
+ def build_yard_pins(gemspec)
50
+ Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
51
+ yardoc = Yardoc.load!(gemspec)
52
+ YardMap::Mapper.new(yardoc, gemspec).map
53
+ end
54
+
55
+ # Select the first defined type.
56
+ #
57
+ # @param choices [Array<ComplexType>]
58
+ # @return [ComplexType]
59
+ def best_return_type *choices
60
+ choices.find { |pin| pin.defined? } || choices.first || ComplexType::UNDEFINED
61
+ end
62
+ end
63
+ end
64
+ end
@@ -6,6 +6,7 @@ module Solargraph
6
6
  # An asynchronous library cataloging handler.
7
7
  #
8
8
  class Cataloger
9
+ # @param host [Host]
9
10
  def initialize host
10
11
  @host = host
11
12
  @stopped = true
@@ -34,7 +35,7 @@ module Solargraph
34
35
  Thread.new do
35
36
  until stopped?
36
37
  tick
37
- sleep 0.01
38
+ sleep 0.1
38
39
  end
39
40
  end
40
41
  end
@@ -38,7 +38,7 @@ module Solargraph
38
38
 
39
39
  # Start the diagnosis thread.
40
40
  #
41
- # @return [self]
41
+ # @return [self, nil]
42
42
  def start
43
43
  return unless @stopped
44
44
  @stopped = false
@@ -81,7 +81,7 @@ module Solargraph
81
81
  # @return [Mutex]
82
82
  attr_reader :mutex
83
83
 
84
- # @return [Array]
84
+ # @return [::Array]
85
85
  attr_reader :queue
86
86
  end
87
87
  end
@@ -6,6 +6,12 @@ module Solargraph
6
6
  # Methods for associating sources with libraries via URIs.
7
7
  #
8
8
  module Dispatch
9
+ # @abstract
10
+ # @return [Host::Diagnoser]
11
+ def diagnoser
12
+ raise NotImplementedError, 'Host::Dispatch requires a diagnoser method'
13
+ end
14
+
9
15
  # @return [Sources]
10
16
  def sources
11
17
  @sources ||= begin
@@ -15,7 +21,7 @@ module Solargraph
15
21
  end
16
22
  end
17
23
 
18
- # @return [Array<Library>]
24
+ # @return [::Array<Library>]
19
25
  def libraries
20
26
  @libraries ||= []
21
27
  end
@@ -27,9 +33,9 @@ module Solargraph
27
33
  # @return [void]
28
34
  def update_libraries uri
29
35
  src = sources.find(uri)
30
- libraries.each do |lib|
31
- lib.merge src if lib.contain?(src.filename)
32
- end
36
+ using = libraries.select { |lib| lib.contain?(src.filename) }
37
+ using.push generic_library_for(uri) if using.empty?
38
+ using.each { |lib| lib.merge src }
33
39
  diagnoser.schedule uri
34
40
  end
35
41
 
@@ -89,6 +95,10 @@ module Solargraph
89
95
  nil
90
96
  end
91
97
 
98
+ def options
99
+ @options ||= {}.freeze
100
+ end
101
+
92
102
  # Get a generic library for the given URI and attach the corresponding
93
103
  # source.
94
104
  #
@@ -103,7 +113,7 @@ module Solargraph
103
113
 
104
114
  # @return [Library]
105
115
  def generic_library
106
- @generic_library ||= Solargraph::Library.new
116
+ @generic_library ||= Solargraph::Library.new(Solargraph::Workspace.new('', nil, options), nil)
107
117
  end
108
118
  end
109
119
  end
@@ -16,6 +16,7 @@ module Solargraph
16
16
  end
17
17
 
18
18
  # pending handle messages
19
+ # @return [Array<Hash>]
19
20
  def messages
20
21
  @messages ||= []
21
22
  end
@@ -24,6 +25,7 @@ module Solargraph
24
25
  @stopped
25
26
  end
26
27
 
28
+ # @return [void]
27
29
  def stop
28
30
  @stopped = true
29
31
  end
@@ -37,6 +39,7 @@ module Solargraph
37
39
  end
38
40
  end
39
41
 
42
+ # @return [void]
40
43
  def start
41
44
  return unless @stopped
42
45
  @stopped = false
@@ -45,6 +48,7 @@ module Solargraph
45
48
  end
46
49
  end
47
50
 
51
+ # @return [void]
48
52
  def tick
49
53
  message = @mutex.synchronize do
50
54
  @resource.wait(@mutex) if messages.empty?
@@ -43,6 +43,7 @@ module Solargraph
43
43
  end
44
44
  end
45
45
 
46
+ # @param uri [String]
46
47
  # @return [void]
47
48
  def add_uri(uri)
48
49
  queue.push(uri)
@@ -72,6 +73,8 @@ module Solargraph
72
73
  open_source_hash[uri] = source
73
74
  end
74
75
 
76
+ # @param uri [String]
77
+ # @return [void]
75
78
  def open_from_disk uri
76
79
  source = Solargraph::Source.load(UriHelpers.uri_to_file(uri))
77
80
  open_source_hash[uri] = source
@@ -83,7 +86,7 @@ module Solargraph
83
86
  #
84
87
  # @param uri [String]
85
88
  # @param updater [Source::Updater]
86
- # @return [Source]
89
+ # @return [void]
87
90
  def update uri, updater
88
91
  src = find(uri)
89
92
  mutex.synchronize { open_source_hash[uri] = src.synchronize(updater) }
@@ -109,7 +112,7 @@ module Solargraph
109
112
  # @raise [FileNotFoundError] if the URI does not match an open source.
110
113
  #
111
114
  # @param uri [String]
112
- # @return [Source]
115
+ # @return [Solargraph::Source]
113
116
  def find uri
114
117
  open_source_hash[uri] || raise(Solargraph::FileNotFoundError, "Host could not find #{uri}")
115
118
  end
@@ -136,7 +139,7 @@ module Solargraph
136
139
 
137
140
  private
138
141
 
139
- # @return [Hash]
142
+ # @return [Hash{String => Solargraph::Source}]
140
143
  def open_source_hash
141
144
  @open_source_hash ||= {}
142
145
  end
@@ -146,7 +149,7 @@ module Solargraph
146
149
 
147
150
  # An array of source URIs that are waiting to finish synchronizing.
148
151
  #
149
- # @return [Array<String>]
152
+ # @return [::Array<String>]
150
153
  def queue
151
154
  @queue ||= []
152
155
  end