solargraph 0.50.0 → 0.53.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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +4 -8
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/.yardopts +2 -2
  6. data/CHANGELOG.md +81 -3
  7. data/README.md +13 -16
  8. data/SPONSORS.md +2 -9
  9. data/lib/solargraph/api_map/cache.rb +60 -20
  10. data/lib/solargraph/api_map/store.rb +47 -11
  11. data/lib/solargraph/api_map.rb +161 -95
  12. data/lib/solargraph/bench.rb +2 -2
  13. data/lib/solargraph/cache.rb +30 -6
  14. data/lib/solargraph/complex_type/type_methods.rb +54 -9
  15. data/lib/solargraph/complex_type/unique_type.rb +154 -57
  16. data/lib/solargraph/complex_type.rb +91 -17
  17. data/lib/solargraph/convention.rb +0 -3
  18. data/lib/solargraph/converters/dd.rb +5 -0
  19. data/lib/solargraph/converters/dl.rb +3 -0
  20. data/lib/solargraph/converters/dt.rb +3 -0
  21. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  22. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  23. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  24. data/lib/solargraph/diagnostics.rb +2 -2
  25. data/lib/solargraph/doc_map.rb +146 -0
  26. data/lib/solargraph/gem_pins.rb +64 -0
  27. data/lib/solargraph/language_server/host/cataloger.rb +1 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +10 -4
  30. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  31. data/lib/solargraph/language_server/host/sources.rb +7 -4
  32. data/lib/solargraph/language_server/host.rb +26 -7
  33. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  34. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  35. data/lib/solargraph/language_server/message/initialize.rb +11 -0
  36. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  37. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  38. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  39. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  40. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  41. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  42. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  43. data/lib/solargraph/language_server/message.rb +1 -0
  44. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  45. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  46. data/lib/solargraph/library.rb +86 -16
  47. data/lib/solargraph/location.rb +1 -0
  48. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  49. data/lib/solargraph/parser/node_methods.rb +47 -7
  50. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  51. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  52. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  53. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  54. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  55. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  56. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  57. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  58. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  60. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +1 -1
  62. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  71. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  73. data/lib/solargraph/parser/parser_gem.rb +12 -0
  74. data/lib/solargraph/parser/region.rb +1 -1
  75. data/lib/solargraph/parser/snippet.rb +2 -0
  76. data/lib/solargraph/parser.rb +9 -10
  77. data/lib/solargraph/pin/base.rb +64 -9
  78. data/lib/solargraph/pin/base_variable.rb +6 -2
  79. data/lib/solargraph/pin/block.rb +19 -9
  80. data/lib/solargraph/pin/closure.rb +17 -2
  81. data/lib/solargraph/pin/common.rb +7 -3
  82. data/lib/solargraph/pin/conversions.rb +33 -3
  83. data/lib/solargraph/pin/delegated_method.rb +97 -0
  84. data/lib/solargraph/pin/documenting.rb +25 -34
  85. data/lib/solargraph/pin/instance_variable.rb +4 -0
  86. data/lib/solargraph/pin/local_variable.rb +13 -1
  87. data/lib/solargraph/pin/method.rb +182 -18
  88. data/lib/solargraph/pin/namespace.rb +18 -5
  89. data/lib/solargraph/pin/parameter.rb +44 -14
  90. data/lib/solargraph/pin/reference/override.rb +2 -2
  91. data/lib/solargraph/pin/reference.rb +8 -0
  92. data/lib/solargraph/pin/search.rb +4 -4
  93. data/lib/solargraph/pin/signature.rb +123 -3
  94. data/lib/solargraph/pin.rb +1 -1
  95. data/lib/solargraph/range.rb +4 -6
  96. data/lib/solargraph/rbs_map/conversions.rb +294 -50
  97. data/lib/solargraph/rbs_map/core_fills.rb +7 -24
  98. data/lib/solargraph/rbs_map/core_map.rb +3 -2
  99. data/lib/solargraph/rbs_map/core_signs.rb +2 -0
  100. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -5
  101. data/lib/solargraph/rbs_map.rb +20 -11
  102. data/lib/solargraph/shell.rb +62 -59
  103. data/lib/solargraph/source/chain/array.rb +32 -0
  104. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  105. data/lib/solargraph/source/chain/call.rb +99 -46
  106. data/lib/solargraph/source/chain/constant.rb +15 -1
  107. data/lib/solargraph/source/chain/if.rb +23 -0
  108. data/lib/solargraph/source/chain/link.rb +8 -2
  109. data/lib/solargraph/source/chain/or.rb +1 -1
  110. data/lib/solargraph/source/chain/z_super.rb +3 -3
  111. data/lib/solargraph/source/chain.rb +29 -14
  112. data/lib/solargraph/source/change.rb +3 -0
  113. data/lib/solargraph/source/cursor.rb +2 -0
  114. data/lib/solargraph/source/source_chainer.rb +8 -5
  115. data/lib/solargraph/source.rb +18 -19
  116. data/lib/solargraph/source_map/clip.rb +25 -23
  117. data/lib/solargraph/source_map/mapper.rb +12 -1
  118. data/lib/solargraph/source_map.rb +30 -7
  119. data/lib/solargraph/type_checker/checks.rb +10 -2
  120. data/lib/solargraph/type_checker.rb +123 -45
  121. data/lib/solargraph/version.rb +1 -1
  122. data/lib/solargraph/workspace/config.rb +14 -11
  123. data/lib/solargraph/workspace.rb +3 -2
  124. data/lib/solargraph/yard_map/cache.rb +6 -0
  125. data/lib/solargraph/yard_map/helpers.rb +1 -1
  126. data/lib/solargraph/yard_map/mapper/to_method.rb +11 -1
  127. data/lib/solargraph/yard_map/mapper.rb +1 -1
  128. data/lib/solargraph/yard_map/to_method.rb +11 -4
  129. data/lib/solargraph/yard_map.rb +1 -284
  130. data/lib/solargraph/yard_tags.rb +20 -0
  131. data/lib/solargraph/yardoc.rb +52 -0
  132. data/lib/solargraph.rb +6 -4
  133. data/solargraph.gemspec +11 -5
  134. metadata +131 -75
  135. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  136. data/lib/solargraph/convention/rspec.rb +0 -30
  137. data/lib/solargraph/documentor.rb +0 -76
  138. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  139. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  140. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  141. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  142. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
  143. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +0 -23
  144. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  145. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  146. data/lib/solargraph/parser/legacy.rb +0 -12
  147. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -149
  148. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  149. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  150. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  151. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  152. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  153. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  154. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  155. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  156. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  157. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  158. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  159. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  160. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  161. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  162. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  163. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  164. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  165. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  166. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  167. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  168. data/lib/solargraph/parser/rubyvm.rb +0 -40
  169. data/lib/yard-solargraph.rb +0 -33
@@ -29,9 +29,9 @@ module Solargraph
29
29
  store = RuboCop::ConfigStore.new
30
30
  runner = RuboCop::Runner.new(options, store)
31
31
  result = redirect_stdout{ runner.run(paths) }
32
-
32
+
33
33
  return [] if result.empty?
34
-
34
+
35
35
  make_array JSON.parse(result)
36
36
  rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
37
37
  raise DiagnosticsError, "Error in RuboCop configuration: #{e.message}"
@@ -48,7 +48,7 @@ module Solargraph
48
48
  args.find { |a| a =~ /version=/ }.to_s.split('=').last
49
49
  end
50
50
 
51
- # @param resp [Hash]
51
+ # @param resp [Hash{String => Array<Hash{String => Array<Hash{String => undefined}>}>}]
52
52
  # @return [Array<Hash>]
53
53
  def make_array resp
54
54
  diagnostics = []
@@ -62,8 +62,8 @@ module Solargraph
62
62
 
63
63
  # Convert a RuboCop offense to an LSP diagnostic
64
64
  #
65
- # @param off [Hash] Offense received from Rubocop
66
- # @return [Hash] LSP diagnostic
65
+ # @param off [Hash{String => unknown}] Offense received from Rubocop
66
+ # @return [Hash{Symbol => Hash, String, Integer}] LSP diagnostic
67
67
  def offense_to_diagnostic off
68
68
  {
69
69
  range: offense_range(off).to_hash,
@@ -81,19 +81,20 @@ module Solargraph
81
81
  Range.new(offense_start_position(off), offense_ending_position(off))
82
82
  end
83
83
 
84
- # @param off [Hash]
84
+ # @param off [Hash{String => Hash{String => Integer}}]
85
85
  # @return [Position]
86
86
  def offense_start_position off
87
87
  Position.new(off['location']['start_line'] - 1, off['location']['start_column'] - 1)
88
88
  end
89
89
 
90
- # @param off [Hash]
90
+ # @param off [Hash{String => Hash{String => Integer}}]
91
91
  # @return [Position]
92
92
  def offense_ending_position off
93
93
  if off['location']['start_line'] != off['location']['last_line']
94
94
  Position.new(off['location']['start_line'], 0)
95
95
  else
96
96
  start_line = off['location']['start_line'] - 1
97
+ # @type [Integer]
97
98
  last_column = off['location']['last_column']
98
99
  line = @source.code.lines[start_line]
99
100
  col_off = if line.nil? || line.empty?
@@ -12,6 +12,7 @@ module Solargraph
12
12
  #
13
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
@@ -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,146 @@
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 :dependencies
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 dependencies [Array<Gem::Specification>]
21
+ def initialize(requires, dependencies)
22
+ @requires = requires
23
+ @dependencies = dependencies
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
+ 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)] }
47
+ end
48
+
49
+ # @return [Hash{String => Gem::Specification}]
50
+ def dependency_map
51
+ @dependency_map ||= dependencies.to_h { |gemspec| [gemspec.name, gemspec] }
52
+ end
53
+
54
+ # @return [void]
55
+ def generate
56
+ @pins = []
57
+ @uncached_gemspecs = []
58
+ required_gem_map.each do |path, gemspec|
59
+ if gemspec
60
+ try_cache gemspec
61
+ else
62
+ try_stdlib_map path
63
+ end
64
+ end
65
+ end
66
+
67
+ # @param gemspec [Gem::Specification]
68
+ # @return [void]
69
+ def try_cache gemspec
70
+ return if try_gem_in_memory(gemspec)
71
+ cache_file = File.join('gems', "#{gemspec.name}-#{gemspec.version}.ser")
72
+ if Cache.exist?(cache_file)
73
+ gempins = Cache.load(cache_file)
74
+ self.class.gems_in_memory[gemspec] = gempins
75
+ @pins.concat gempins
76
+ else
77
+ Solargraph.logger.debug "No pin cache for #{gemspec.name} #{gemspec.version}"
78
+ @uncached_gemspecs.push gemspec
79
+ end
80
+ end
81
+
82
+ # @param path [String] require path that might be in the RBS stdlib collection
83
+ # @return [void]
84
+ def try_stdlib_map path
85
+ map = RbsMap::StdlibMap.load(path)
86
+ if map.resolved?
87
+ Solargraph.logger.debug "Loading stdlib pins for #{path}"
88
+ @pins.concat map.pins
89
+ else
90
+ # @todo Temporarily ignoring unresolved `require 'set'`
91
+ Solargraph.logger.warn "Require path #{path} could not be resolved" unless path == 'set'
92
+ end
93
+ end
94
+
95
+ # @param gemspec [Gem::Specification]
96
+ # @return [Boolean]
97
+ def try_gem_in_memory gemspec
98
+ gempins = DocMap.gems_in_memory[gemspec]
99
+ return false unless gempins
100
+ Solargraph.logger.debug "Found #{gemspec.name} #{gemspec.version} in memory"
101
+ @pins.concat gempins
102
+ true
103
+ end
104
+
105
+ # @param path [String]
106
+ # @return [Gem::Specification, nil]
107
+ def resolve_path_to_gemspec path
108
+ gemspec = Gem::Specification.find_by_path(path)
109
+ if gemspec.nil?
110
+ gem_name_guess = path.split('/').first
111
+ begin
112
+ # this can happen when the gem is included via a local path in
113
+ # a Gemfile; Gem doesn't try to index the paths in that case.
114
+ #
115
+ # See if we can make a good guess:
116
+ potential_gemspec = Gem::Specification.find_by_name(gem_name_guess)
117
+ file = "lib/#{path}.rb"
118
+ gemspec = potential_gemspec if potential_gemspec.files.any? { |gemspec_file| file == gemspec_file }
119
+ rescue Gem::MissingSpecError
120
+ Solargraph.logger.debug "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}"
121
+ nil
122
+ end
123
+ end
124
+ return gemspec if dependencies.empty? || gemspec.nil?
125
+
126
+ if dependency_map.key?(gemspec.name)
127
+ return gemspec if gemspec.version == dependency_map[gemspec.name].version
128
+
129
+ change_gemspec_version gemspec, dependency_map[by_path.name].version
130
+ else
131
+ Solargraph.logger.warn "Gem #{gemspec.name} is not an expected dependency"
132
+ gemspec
133
+ end
134
+ end
135
+
136
+ # @param gemspec [Gem::Specification]
137
+ # @param version [Gem::Version]
138
+ # @return [Gem::Specification]
139
+ def change_gemspec_version gemspec, version
140
+ Gem::Specification.find_by_name(gemspec.name, "= #{version}")
141
+ rescue Gem::MissingSpecError
142
+ Solargraph.logger.info "Gem #{gemspec.name} version #{version} not found. Using #{gemspec.version} instead"
143
+ gemspec
144
+ end
145
+ end
146
+ 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)
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
@@ -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
 
@@ -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
@@ -3,7 +3,6 @@
3
3
  require 'diff/lcs'
4
4
  require 'observer'
5
5
  require 'securerandom'
6
- require 'set'
7
6
 
8
7
  module Solargraph
9
8
  module LanguageServer
@@ -59,7 +58,7 @@ module Solargraph
59
58
  logger.level = LOG_LEVELS[options['logLevel']] || DEFAULT_LOG_LEVEL
60
59
  end
61
60
 
62
- # @return [Hash]
61
+ # @return [Hash{String => [Boolean, String]}]
63
62
  def options
64
63
  @options ||= default_configuration
65
64
  end
@@ -101,8 +100,8 @@ module Solargraph
101
100
  # Start processing a request from the client. After the message is
102
101
  # processed, caller is responsible for sending the response.
103
102
  #
104
- # @param request [Hash] The contents of the message.
105
- # @return [Solargraph::LanguageServer::Message::Base] The message handler.
103
+ # @param request [Hash{String => unspecified}] The contents of the message.
104
+ # @return [Solargraph::LanguageServer::Message::Base, nil] The message handler.
106
105
  def receive request
107
106
  if request['method']
108
107
  logger.info "Server received #{request['method']}"
@@ -127,6 +126,7 @@ module Solargraph
127
126
  else
128
127
  logger.warn "Invalid message received."
129
128
  logger.debug request
129
+ nil
130
130
  end
131
131
  end
132
132
 
@@ -505,6 +505,8 @@ module Solargraph
505
505
  library.read_text(filename)
506
506
  end
507
507
 
508
+ # @param uri [String]
509
+ # @return [Hash]
508
510
  def formatter_config uri
509
511
  library = library_for(uri)
510
512
  library.workspace.config.formatter
@@ -533,6 +535,15 @@ module Solargraph
533
535
  library.definitions_at(uri_to_file(uri), line, column)
534
536
  end
535
537
 
538
+ # @param uri [String]
539
+ # @param line [Integer]
540
+ # @param column [Integer]
541
+ # @return [Array<Solargraph::Pin::Base>]
542
+ def type_definitions_at uri, line, column
543
+ library = library_for(uri)
544
+ library.type_definitions_at(uri_to_file(uri), line, column)
545
+ end
546
+
536
547
  # @param uri [String]
537
548
  # @param line [Integer]
538
549
  # @param column [Integer]
@@ -623,17 +634,18 @@ module Solargraph
623
634
  requests.keys
624
635
  end
625
636
 
626
- # @return [Hash{String => Object}]
637
+ # @return [Hash{String => [Boolean,String]}]
627
638
  def default_configuration
628
639
  {
629
640
  'completion' => true,
630
641
  'hover' => true,
631
642
  'symbols' => true,
632
643
  'definitions' => true,
644
+ 'typeDefinitions' => true,
633
645
  'rename' => true,
634
646
  'references' => true,
635
647
  'autoformat' => false,
636
- 'diagnostics' => false,
648
+ 'diagnostics' => true,
637
649
  'formatting' => false,
638
650
  'folding' => true,
639
651
  'highlights' => true,
@@ -653,6 +665,7 @@ module Solargraph
653
665
  libraries.each(&:catalog)
654
666
  end
655
667
 
668
+ # @return [Hash{String => BasicObject}]
656
669
  def client_capabilities
657
670
  @client_capabilities ||= {}
658
671
  end
@@ -677,7 +690,7 @@ module Solargraph
677
690
  # A hash of client requests by ID. The host uses this to keep track of
678
691
  # pending responses.
679
692
  #
680
- # @return [Hash{Integer => Hash}]
693
+ # @return [Hash{Integer => Solargraph::LanguageServer::Host}]
681
694
  def requests
682
695
  @requests ||= {}
683
696
  end
@@ -769,6 +782,9 @@ module Solargraph
769
782
  'textDocument/definition' => {
770
783
  definitionProvider: true
771
784
  },
785
+ 'textDocument/typeDefinition' => {
786
+ typeDefinitionProvider: true
787
+ },
772
788
  'textDocument/references' => {
773
789
  referencesProvider: true
774
790
  },
@@ -822,6 +838,9 @@ module Solargraph
822
838
  end
823
839
  end
824
840
 
841
+ # @param library [Library]
842
+ # @param uuid [String, nil]
843
+ # @return [void]
825
844
  def do_async_library_map library, uuid = nil
826
845
  total = library.workspace.sources.length
827
846
  if uuid
@@ -29,7 +29,7 @@ module Solargraph
29
29
  end
30
30
 
31
31
  # @param text [String]
32
- # @return [Hash{Symbol => String}]
32
+ # @return [Hash{Symbol => String}, nil]
33
33
  def markup_content text
34
34
  return nil if text.strip.empty?
35
35
  {
@@ -38,6 +38,8 @@ module Solargraph
38
38
  }
39
39
  end
40
40
 
41
+ # @param pins [Array<Pin::Base>]
42
+ # @return [String]
41
43
  def join_docs pins
42
44
  result = []
43
45
  last_link = nil
@@ -1,6 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubygems'
3
+
4
+ # @todo PR the RBS gem to add this
5
+ # @!parse
6
+ # module ::Gem
7
+ # class SpecFetcher; end
8
+ # end
4
9
 
5
10
  module Solargraph
6
11
  module LanguageServer
@@ -11,16 +16,23 @@ module Solargraph
11
16
  # is true, notify the client when the gem is up to date.
12
17
  #
13
18
  class CheckGemVersion < Base
19
+ # @return [Gem::SpecFetcher]
14
20
  def self.fetcher
15
21
  @fetcher ||= Gem::SpecFetcher.new
16
22
  end
17
23
 
24
+ # @param obj [Gem::SpecFetcher]
25
+ # @return [Gem::SpecFetcher]
18
26
  def self.fetcher= obj
19
27
  @fetcher = obj
20
28
  end
21
29
 
22
30
  GEM_ZERO = Gem::Version.new('0.0.0')
23
31
 
32
+ # @param host [Solargraph::LanguageServer::Host]
33
+ # @param request [Hash]
34
+ # @param current [Gem::Version]
35
+ # @param available [Gem::Version, nil]
24
36
  def initialize host, request, current: Gem::Version.new(Solargraph::VERSION), available: nil
25
37
  super(host, request)
26
38
  @current = current
@@ -34,6 +34,7 @@ module Solargraph
34
34
  result[:capabilities].merge! static_document_formatting unless dynamic_registration_for?('textDocument', 'formatting')
35
35
  result[:capabilities].merge! static_document_symbols unless dynamic_registration_for?('textDocument', 'documentSymbol')
36
36
  result[:capabilities].merge! static_definitions unless dynamic_registration_for?('textDocument', 'definition')
37
+ result[:capabilities].merge! static_type_definitions unless dynamic_registration_for?('textDocument', 'typeDefinition')
37
38
  result[:capabilities].merge! static_rename unless dynamic_registration_for?('textDocument', 'rename')
38
39
  result[:capabilities].merge! static_references unless dynamic_registration_for?('textDocument', 'references')
39
40
  result[:capabilities].merge! static_workspace_symbols unless dynamic_registration_for?('workspace', 'symbol')
@@ -53,6 +54,7 @@ module Solargraph
53
54
  params['workspaceFolders']
54
55
  end
55
56
 
57
+ # @return [Hash{Symbol => undefined}]
56
58
  def static_completion
57
59
  return {} unless host.options['completion']
58
60
  {
@@ -63,6 +65,7 @@ module Solargraph
63
65
  }
64
66
  end
65
67
 
68
+ # @return [Hash{Symbol => BasicObject}]
66
69
  def static_code_action
67
70
  {
68
71
  codeActionProvider: true,
@@ -70,6 +73,7 @@ module Solargraph
70
73
  }
71
74
  end
72
75
 
76
+ # @return [Hash{Symbol => BasicObject}]
73
77
  def static_signature_help
74
78
  {
75
79
  signatureHelpProvider: {
@@ -121,6 +125,13 @@ module Solargraph
121
125
  }
122
126
  end
123
127
 
128
+ def static_type_definitions
129
+ return {} unless host.options['typeDefinitions']
130
+ {
131
+ typeDefinitionProvider: true
132
+ }
133
+ end
134
+
124
135
  def static_rename
125
136
  {
126
137
  renameProvider: {prepareProvider: true}
@@ -13,6 +13,7 @@ module Solargraph
13
13
  textDocument/formatting
14
14
  textDocument/documentSymbol
15
15
  textDocument/definition
16
+ textDocument/typeDefinition
16
17
  textDocument/references
17
18
  textDocument/rename
18
19
  textDocument/prepareRename