solargraph 0.56.2 → 0.57.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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +148 -6
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +5 -2
  6. data/.gitignore +5 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +2627 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +42 -0
  13. data/README.md +8 -4
  14. data/Rakefile +125 -13
  15. data/lib/solargraph/api_map/cache.rb +3 -2
  16. data/lib/solargraph/api_map/constants.rb +218 -0
  17. data/lib/solargraph/api_map/index.rb +20 -26
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +126 -18
  20. data/lib/solargraph/api_map.rb +212 -234
  21. data/lib/solargraph/bench.rb +1 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +1 -0
  23. data/lib/solargraph/complex_type/unique_type.rb +7 -7
  24. data/lib/solargraph/complex_type.rb +5 -1
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +17 -0
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -0
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
  29. data/lib/solargraph/convention/data_definition.rb +2 -1
  30. data/lib/solargraph/convention/gemspec.rb +1 -1
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +3 -1
  33. data/lib/solargraph/convention/struct_definition.rb +36 -13
  34. data/lib/solargraph/convention.rb +31 -2
  35. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  36. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  37. data/lib/solargraph/doc_map.rb +40 -12
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +17 -11
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +3 -0
  42. data/lib/solargraph/language_server/host.rb +2 -1
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
  45. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  46. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  48. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  49. data/lib/solargraph/language_server/progress.rb +8 -0
  50. data/lib/solargraph/language_server/request.rb +1 -0
  51. data/lib/solargraph/library.rb +8 -15
  52. data/lib/solargraph/location.rb +2 -0
  53. data/lib/solargraph/logging.rb +11 -2
  54. data/lib/solargraph/page.rb +4 -0
  55. data/lib/solargraph/parser/comment_ripper.rb +8 -1
  56. data/lib/solargraph/parser/flow_sensitive_typing.rb +32 -4
  57. data/lib/solargraph/parser/node_methods.rb +2 -2
  58. data/lib/solargraph/parser/node_processor/base.rb +1 -1
  59. data/lib/solargraph/parser/node_processor.rb +6 -2
  60. data/lib/solargraph/parser/parser_gem/class_methods.rb +1 -1
  61. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  62. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
  63. data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
  64. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
  65. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
  66. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +35 -14
  68. data/lib/solargraph/parser/region.rb +3 -0
  69. data/lib/solargraph/parser/snippet.rb +2 -0
  70. data/lib/solargraph/pin/base.rb +50 -8
  71. data/lib/solargraph/pin/base_variable.rb +1 -2
  72. data/lib/solargraph/pin/callable.rb +9 -0
  73. data/lib/solargraph/pin/closure.rb +2 -0
  74. data/lib/solargraph/pin/common.rb +6 -2
  75. data/lib/solargraph/pin/constant.rb +2 -0
  76. data/lib/solargraph/pin/delegated_method.rb +1 -0
  77. data/lib/solargraph/pin/local_variable.rb +4 -1
  78. data/lib/solargraph/pin/method.rb +8 -5
  79. data/lib/solargraph/pin/method_alias.rb +3 -0
  80. data/lib/solargraph/pin/parameter.rb +18 -8
  81. data/lib/solargraph/pin/proxy_type.rb +1 -0
  82. data/lib/solargraph/pin/reference/override.rb +15 -1
  83. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  84. data/lib/solargraph/pin/reference.rb +26 -0
  85. data/lib/solargraph/pin/search.rb +3 -1
  86. data/lib/solargraph/pin/signature.rb +2 -0
  87. data/lib/solargraph/pin/symbol.rb +5 -0
  88. data/lib/solargraph/pin_cache.rb +64 -4
  89. data/lib/solargraph/position.rb +2 -0
  90. data/lib/solargraph/range.rb +1 -0
  91. data/lib/solargraph/rbs_map/conversions.rb +7 -5
  92. data/lib/solargraph/rbs_map/core_map.rb +3 -0
  93. data/lib/solargraph/rbs_map.rb +15 -2
  94. data/lib/solargraph/shell.rb +3 -0
  95. data/lib/solargraph/source/chain/link.rb +10 -1
  96. data/lib/solargraph/source/chain.rb +9 -2
  97. data/lib/solargraph/source/change.rb +2 -2
  98. data/lib/solargraph/source/cursor.rb +2 -3
  99. data/lib/solargraph/source/source_chainer.rb +1 -1
  100. data/lib/solargraph/source.rb +5 -2
  101. data/lib/solargraph/source_map/clip.rb +1 -1
  102. data/lib/solargraph/source_map/data.rb +4 -0
  103. data/lib/solargraph/source_map/mapper.rb +4 -2
  104. data/lib/solargraph/source_map.rb +21 -14
  105. data/lib/solargraph/type_checker/param_def.rb +2 -0
  106. data/lib/solargraph/type_checker/rules.rb +8 -0
  107. data/lib/solargraph/type_checker.rb +173 -120
  108. data/lib/solargraph/version.rb +1 -1
  109. data/lib/solargraph/workspace/config.rb +0 -2
  110. data/lib/solargraph/workspace/require_paths.rb +98 -0
  111. data/lib/solargraph/workspace.rb +16 -48
  112. data/lib/solargraph/yard_map/mapper/to_method.rb +2 -2
  113. data/lib/solargraph/yardoc.rb +16 -3
  114. data/lib/solargraph.rb +2 -0
  115. data/rbs/fills/tuple.rbs +2 -3
  116. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  117. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  118. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  119. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  120. data/solargraph.gemspec +14 -4
  121. metadata +123 -9
  122. data/lib/.rubocop.yml +0 -22
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'benchmark'
5
+ require 'open3'
5
6
 
6
7
  module Solargraph
7
8
  # A collection of pins generated from required gems.
@@ -32,8 +33,10 @@ module Solargraph
32
33
  # @return [Array<Gem::Specification>]
33
34
  attr_reader :uncached_rbs_collection_gemspecs
34
35
 
36
+ # @return [String, nil]
35
37
  attr_reader :rbs_collection_path
36
38
 
39
+ # @return [String, nil]
37
40
  attr_reader :rbs_collection_config_path
38
41
 
39
42
  # @return [Workspace, nil]
@@ -52,10 +55,13 @@ module Solargraph
52
55
  @rbs_collection_path = workspace&.rbs_collection_path
53
56
  @rbs_collection_config_path = workspace&.rbs_collection_config_path
54
57
  @environ = Convention.for_global(self)
58
+ @requires.concat @environ.requires if @environ
55
59
  load_serialized_gem_pins
56
60
  pins.concat @environ.pins
57
61
  end
58
62
 
63
+ # @param out [IO]
64
+ # @return [void]
59
65
  def cache_all!(out)
60
66
  # if we log at debug level:
61
67
  if logger.info?
@@ -73,12 +79,18 @@ module Solargraph
73
79
  @uncached_yard_gemspecs = []
74
80
  end
75
81
 
82
+ # @param gemspec [Gem::Specification]
83
+ # @param out [IO]
84
+ # @return [void]
76
85
  def cache_yard_pins(gemspec, out)
77
- pins = GemPins.build_yard_pins(gemspec)
86
+ pins = GemPins.build_yard_pins(yard_plugins, gemspec)
78
87
  PinCache.serialize_yard_gem(gemspec, pins)
79
88
  logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
80
89
  end
81
90
 
91
+ # @param gemspec [Gem::Specification]
92
+ # @param out [IO]
93
+ # @return [void]
82
94
  def cache_rbs_collection_pins(gemspec, out)
83
95
  rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
84
96
  pins = rbs_map.pins
@@ -90,6 +102,9 @@ module Solargraph
90
102
  end
91
103
 
92
104
  # @param gemspec [Gem::Specification]
105
+ # @param rebuild [Boolean] whether to rebuild the pins even if they are cached
106
+ # @param out [IO, nil] output stream for logging
107
+ # @return [void]
93
108
  def cache(gemspec, rebuild: false, out: nil)
94
109
  build_yard = uncached_yard_gemspecs.include?(gemspec) || rebuild
95
110
  build_rbs_collection = uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
@@ -113,30 +128,42 @@ module Solargraph
113
128
  @unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
114
129
  end
115
130
 
131
+ # @return [Hash{Array(String, String) => Array<Gem::Specification>}] Indexed by gemspec name and version
116
132
  def self.all_yard_gems_in_memory
117
133
  @yard_gems_in_memory ||= {}
118
134
  end
119
135
 
136
+ # @return [Hash{String => Hash{Array(String, String) => Array<Pin::Base>}}] stored by RBS collection path
120
137
  def self.all_rbs_collection_gems_in_memory
121
138
  @rbs_collection_gems_in_memory ||= {}
122
139
  end
123
140
 
141
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
124
142
  def yard_pins_in_memory
125
143
  self.class.all_yard_gems_in_memory
126
144
  end
127
145
 
146
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
128
147
  def rbs_collection_pins_in_memory
129
148
  self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
130
149
  end
131
150
 
151
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
132
152
  def self.all_combined_pins_in_memory
133
153
  @combined_pins_in_memory ||= {}
134
154
  end
135
155
 
156
+ # @todo this should also include an index by the hash of the RBS collection
157
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
136
158
  def combined_pins_in_memory
137
159
  self.class.all_combined_pins_in_memory
138
160
  end
139
161
 
162
+ # @return [Array<String>]
163
+ def yard_plugins
164
+ @environ.yard_plugins
165
+ end
166
+
140
167
  # @return [Set<Gem::Specification>]
141
168
  def dependencies
142
169
  @dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
@@ -150,7 +177,11 @@ module Solargraph
150
177
  @uncached_yard_gemspecs = []
151
178
  @uncached_rbs_collection_gemspecs = []
152
179
  with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
180
+ # @sg-ignore Wrong argument type for Hash.[]: arg_0 expected _ToHash<Array(String, Array<Gem::Specification>), undefined>, received Array<Array(String, Array<Gem::Specification>)>
181
+ # @type [Array<String>]
153
182
  paths = Hash[without_gemspecs].keys
183
+ # @sg-ignore Wrong argument type for Hash.[]: arg_0 expected _ToHash<Array(String, Array<Gem::Specification>), undefined>, received Array<Array(String, Array<Gem::Specification>)>
184
+ # @type [Array<Gem::Specification>]
154
185
  gemspecs = Hash[with_gemspecs].values.flatten.compact + dependencies.to_a
155
186
 
156
187
  paths.each do |path|
@@ -259,6 +290,8 @@ module Solargraph
259
290
  end
260
291
  end
261
292
 
293
+ # @param gemspec [Gem::Specification]
294
+ # @param rbs_version_cache_key [String]
262
295
  # @return [Array<Pin::Base>, nil]
263
296
  def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
264
297
  return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
@@ -274,22 +307,13 @@ module Solargraph
274
307
  end
275
308
  end
276
309
 
277
- # @param gemspec [Gem::Specification]
278
- # @return [Boolean]
279
- def try_gem_in_memory gemspec
280
- gempins = DocMap.gems_in_memory[gemspec]
281
- return false unless gempins
282
- Solargraph.logger.debug "Found #{gemspec.name} #{gemspec.version} in memory"
283
- @pins.concat gempins
284
- true
285
- end
286
-
287
310
  # @param path [String]
288
311
  # @return [::Array<Gem::Specification>, nil]
289
312
  def resolve_path_to_gemspecs path
290
313
  return nil if path.empty?
291
314
  return gemspecs_required_from_bundler if path == 'bundler/require'
292
315
 
316
+ # @type [Gem::Specification, nil]
293
317
  gemspec = Gem::Specification.find_by_path(path)
294
318
  if gemspec.nil?
295
319
  gem_name_guess = path.split('/').first
@@ -313,10 +337,12 @@ module Solargraph
313
337
  # @param gemspec [Gem::Specification]
314
338
  # @return [Gem::Specification]
315
339
  def gemspec_or_preference gemspec
340
+ # :nocov: dormant feature
316
341
  return gemspec unless preference_map.key?(gemspec.name)
317
342
  return gemspec if gemspec.version == preference_map[gemspec.name].version
318
343
 
319
- change_gemspec_version gemspec, preference_map[by_path.name].version
344
+ change_gemspec_version gemspec, preference_map[gemspec.name].version
345
+ # :nocov:
320
346
  end
321
347
 
322
348
  # @param gemspec [Gem::Specification]
@@ -355,6 +381,7 @@ module Solargraph
355
381
  self.class.inspect
356
382
  end
357
383
 
384
+ # @return [Array<Gem::Specification>]
358
385
  def gemspecs_required_from_bundler
359
386
  # @todo Handle projects with custom Bundler/Gemfile setups
360
387
  return unless workspace.gemfile?
@@ -377,6 +404,7 @@ module Solargraph
377
404
  end
378
405
  end
379
406
 
407
+ # @return [Array<Gem::Specification>]
380
408
  def gemspecs_required_from_external_bundle
381
409
  logger.info 'Fetching gemspecs required from external bundle'
382
410
  return [] unless workspace&.directory
@@ -13,16 +13,21 @@ module Solargraph
13
13
  # @return [Array<String>]
14
14
  attr_reader :domains
15
15
 
16
- # @return [Array<Pin::Reference::Override>]
16
+ # @return [Array<Pin::Base>]
17
17
  attr_reader :pins
18
18
 
19
+ # @return [Array<String>]
20
+ attr_reader :yard_plugins
21
+
19
22
  # @param requires [Array<String>]
20
23
  # @param domains [Array<String>]
21
24
  # @param pins [Array<Pin::Base>]
22
- def initialize requires: [], domains: [], pins: []
25
+ # @param yard_plugins[Array<String>]
26
+ def initialize requires: [], domains: [], pins: [], yard_plugins: []
23
27
  @requires = requires
24
28
  @domains = domains
25
29
  @pins = pins
30
+ @yard_plugins = yard_plugins
26
31
  end
27
32
 
28
33
  # @return [self]
@@ -30,6 +35,7 @@ module Solargraph
30
35
  domains.clear
31
36
  requires.clear
32
37
  pins.clear
38
+ yard_plugins.clear
33
39
  self
34
40
  end
35
41
 
@@ -39,6 +45,7 @@ module Solargraph
39
45
  domains.concat other.domains
40
46
  requires.concat other.requires
41
47
  pins.concat other.pins
48
+ yard_plugins.concat other.yard_plugins
42
49
  self
43
50
  end
44
51
  end
@@ -11,17 +11,9 @@ module Solargraph
11
11
  include Logging
12
12
  end
13
13
 
14
- # @param gemspec [Gem::Specification]
15
- # @return [Array<Pin::Base>]
16
- def self.build_yard_pins(gemspec)
17
- Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
18
- yardoc = Yardoc.load!(gemspec)
19
- YardMap::Mapper.new(yardoc, gemspec).map
20
- end
21
-
22
14
  # @param pins [Array<Pin::Base>]
15
+ # @return [Array<Pin::Base>]
23
16
  def self.combine_method_pins_by_path(pins)
24
- # bad_pins = pins.select { |pin| pin.is_a?(Pin::Method) && pin.path == 'StringIO.open' && pin.source == :rbs }; raise "wtf: #{bad_pins}" if bad_pins.length > 1
25
17
  method_pins, alias_pins = pins.partition { |pin| pin.class == Pin::Method }
26
18
  by_path = method_pins.group_by(&:path)
27
19
  by_path.transform_values! do |pins|
@@ -30,8 +22,12 @@ module Solargraph
30
22
  by_path.values + alias_pins
31
23
  end
32
24
 
25
+ # @param pins [Array<Pin::Method>]
26
+ # @return [Pin::Method, nil]
33
27
  def self.combine_method_pins(*pins)
34
- out = pins.reduce(nil) do |memo, pin|
28
+ # @type [Pin::Method, nil]
29
+ combined_pin = nil
30
+ out = pins.reduce(combined_pin) do |memo, pin|
35
31
  next pin if memo.nil?
36
32
  if memo == pin && memo.source != :combined
37
33
  # @todo we should track down situations where we are handled
@@ -45,8 +41,18 @@ module Solargraph
45
41
  out
46
42
  end
47
43
 
44
+ # @param yard_plugins [Array<String>] The names of YARD plugins to use.
45
+ # @param gemspec [Gem::Specification]
46
+ # @return [Array<Pin::Base>]
47
+ def self.build_yard_pins(yard_plugins, gemspec)
48
+ Yardoc.cache(yard_plugins, gemspec) unless Yardoc.cached?(gemspec)
49
+ yardoc = Yardoc.load!(gemspec)
50
+ YardMap::Mapper.new(yardoc, gemspec).map
51
+ end
52
+
48
53
  # @param yard_pins [Array<Pin::Base>]
49
- # @param rbs_map [RbsMap]
54
+ # @param rbs_pins [Array<Pin::Base>]
55
+ #
50
56
  # @return [Array<Pin::Base>]
51
57
  def self.combine(yard_pins, rbs_pins)
52
58
  in_yard = Set.new
@@ -95,6 +95,7 @@ module Solargraph
95
95
  nil
96
96
  end
97
97
 
98
+ # @return [Hash{String => undefined}]
98
99
  def options
99
100
  @options ||= {}.freeze
100
101
  end
@@ -118,6 +119,7 @@ module Solargraph
118
119
  end
119
120
 
120
121
  # @param library [Solargraph::Library]
122
+ # @param progress [Solargraph::LanguageServer::Progress, nil]
121
123
  # @return [void]
122
124
  def update progress
123
125
  progress&.send(self)
@@ -72,10 +72,12 @@ module Solargraph
72
72
 
73
73
  private
74
74
 
75
+ # @return [Hash, nil]
75
76
  def next_message
76
77
  cancel_message || next_priority
77
78
  end
78
79
 
80
+ # @return [Hash, nil]
79
81
  def cancel_message
80
82
  # Handle cancellations first
81
83
  idx = messages.find_index { |msg| msg['method'] == '$/cancelRequest' }
@@ -86,6 +88,7 @@ module Solargraph
86
88
  msg
87
89
  end
88
90
 
91
+ # @return [Hash, nil]
89
92
  def next_priority
90
93
  # Prioritize updates and version-dependent messages for performance
91
94
  idx = messages.find_index do |msg|
@@ -299,6 +299,7 @@ module Solargraph
299
299
  end
300
300
  end
301
301
 
302
+ # @return [String]
302
303
  def command_path
303
304
  options['commandPath'] || 'solargraph'
304
305
  end
@@ -716,7 +717,7 @@ module Solargraph
716
717
  # A hash of client requests by ID. The host uses this to keep track of
717
718
  # pending responses.
718
719
  #
719
- # @return [Hash{Integer => Solargraph::LanguageServer::Host}]
720
+ # @return [Hash{Integer => Solargraph::LanguageServer::Request}]
720
721
  def requests
721
722
  @requests ||= {}
722
723
  end
@@ -16,7 +16,7 @@ module Solargraph
16
16
  # @return [String]
17
17
  attr_reader :method
18
18
 
19
- # @return [Hash{String => Array<undefined>, Hash{String => undefined}, String, Integer}]
19
+ # @return [Hash{String => undefined}]
20
20
  attr_reader :params
21
21
 
22
22
  # @return [Hash, Array, nil]
@@ -79,6 +79,7 @@ module Solargraph
79
79
 
80
80
  private
81
81
 
82
+ # @return [void]
82
83
  def accept_or_cancel
83
84
  if host.cancel?(id)
84
85
  # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
@@ -83,7 +83,7 @@ module Solargraph
83
83
  @fetched = true
84
84
  begin
85
85
  @available ||= begin
86
- # @sg-ignore
86
+ # @sg-ignore Variable type could not be inferred for tuple
87
87
  # @type [Gem::Dependency, nil]
88
88
  tuple = CheckGemVersion.fetcher.search_for_dependency(Gem::Dependency.new('solargraph')).flatten.first
89
89
  if tuple.nil?
@@ -10,6 +10,7 @@ module Solargraph::LanguageServer::Message::TextDocument
10
10
 
11
11
  private
12
12
 
13
+ # @return [Array<Hash>]
13
14
  def code_location
14
15
  suggestions = host.definitions_at(params['textDocument']['uri'], @line, @column)
15
16
  return nil if suggestions.empty?
@@ -21,6 +22,7 @@ module Solargraph::LanguageServer::Message::TextDocument
21
22
  end
22
23
  end
23
24
 
25
+ # @return [Array<Hash>]
24
26
  def require_location
25
27
  # @todo Terrible hack
26
28
  lib = host.library_for(params['textDocument']['uri'])
@@ -19,8 +19,14 @@ module Solargraph
19
19
  require_rubocop(config['version'])
20
20
  options, paths = ::RuboCop::Options.new.parse(args)
21
21
  options[:stdin] = original
22
- corrections = redirect_stdout do
23
- ::RuboCop::Runner.new(options, ::RuboCop::ConfigStore.new).run(paths)
22
+
23
+ # Ensure only one instance of RuboCop::Runner is running at
24
+ # a time - it uses 'chdir' to read config files with ERB,
25
+ # which can conflict with other chdirs.
26
+ corrections = Solargraph::CHDIR_MUTEX.synchronize do
27
+ redirect_stdout do
28
+ ::RuboCop::Runner.new(options, ::RuboCop::ConfigStore.new).run(paths)
29
+ end
24
30
  end
25
31
  result = options[:stdin]
26
32
 
@@ -34,6 +40,7 @@ module Solargraph
34
40
  private
35
41
 
36
42
  # @param corrections [String]
43
+ # @return [void]
37
44
  def log_corrections(corrections)
38
45
  corrections = corrections&.strip
39
46
  return if corrections&.empty?
@@ -45,6 +52,8 @@ module Solargraph
45
52
  end
46
53
  end
47
54
 
55
+ # @param file_uri [String]
56
+ # @return [Hash{String => undefined}]
48
57
  def config_for(file_uri)
49
58
  conf = host.formatter_config(file_uri)
50
59
  return {} unless conf.is_a?(Hash)
@@ -52,7 +61,9 @@ module Solargraph
52
61
  conf['rubocop'] || {}
53
62
  end
54
63
 
64
+ # @param file_uri [String]
55
65
  # @param config [Hash{String => String}]
66
+ # @return [Array<String>]
56
67
  def cli_args file_uri, config
57
68
  file = UriHelpers.uri_to_file(file_uri)
58
69
  args = [
@@ -71,6 +82,8 @@ module Solargraph
71
82
  end
72
83
 
73
84
  # @param config [Hash{String => String}]
85
+ # @sg-ignore
86
+ # @return [Class<RuboCop::Formatter::BaseFormatter>]
74
87
  def formatter_class(config)
75
88
  if self.class.const_defined?('BlankRubocopFormatter')
76
89
  # @sg-ignore
@@ -83,6 +96,7 @@ module Solargraph
83
96
  end
84
97
 
85
98
  # @param value [Array, String]
99
+ # @return [String]
86
100
  def cop_list(value)
87
101
  value = value.join(',') if value.respond_to?(:join)
88
102
  return nil if value == '' || !value.is_a?(String)
@@ -10,6 +10,7 @@ module Solargraph::LanguageServer::Message::TextDocument
10
10
 
11
11
  private
12
12
 
13
+ # @return [Array<Hash>]
13
14
  def code_location
14
15
  suggestions = host.type_definitions_at(params['textDocument']['uri'], @line, @column)
15
16
  return nil if suggestions.empty?
@@ -9,11 +9,13 @@ module Solargraph::LanguageServer::Message::Workspace
9
9
 
10
10
  private
11
11
 
12
+ # @return [void]
12
13
  def add_folders
13
14
  return unless params['event'] && params['event']['added']
14
15
  host.prepare_folders params['event']['added']
15
16
  end
16
17
 
18
+ # @return [void]
17
19
  def remove_folders
18
20
  return unless params['event'] && params['event']['removed']
19
21
  params['event']['removed'].each do |folder|
@@ -39,6 +39,7 @@ module Solargraph
39
39
 
40
40
  # @param message [String]
41
41
  # @param percentage [Integer]
42
+ # @return [void]
42
43
  def begin message, percentage
43
44
  @kind = 'begin'
44
45
  @message = message
@@ -47,6 +48,7 @@ module Solargraph
47
48
 
48
49
  # @param message [String]
49
50
  # @param percentage [Integer]
51
+ # @return [void]
50
52
  def report message, percentage
51
53
  @kind = 'report'
52
54
  @message = message
@@ -54,6 +56,7 @@ module Solargraph
54
56
  end
55
57
 
56
58
  # @param message [String]
59
+ # @return [void]
57
60
  def finish message
58
61
  @kind = 'end'
59
62
  @message = message
@@ -62,6 +65,7 @@ module Solargraph
62
65
  end
63
66
 
64
67
  # @param host [Solargraph::LanguageServer::Host]
68
+ # @return [void]
65
69
  def send host
66
70
  return unless host.client_supports_progress? && !finished?
67
71
 
@@ -91,6 +95,7 @@ module Solargraph
91
95
  @status = CREATED
92
96
  end
93
97
 
98
+ # @return [Hash]
94
99
  def build
95
100
  {
96
101
  token: uuid,
@@ -101,6 +106,7 @@ module Solargraph
101
106
  }
102
107
  end
103
108
 
109
+ # @return [Hash]
104
110
  def build_value
105
111
  case kind
106
112
  when 'begin'
@@ -115,6 +121,7 @@ module Solargraph
115
121
  end
116
122
 
117
123
  # @param host [Host]
124
+ # @return [void]
118
125
  def keep_alive host
119
126
  mutex.synchronize { @last = Time.now }
120
127
  @keep_alive ||= Thread.new do
@@ -127,6 +134,7 @@ module Solargraph
127
134
  end
128
135
  end
129
136
 
137
+ # @return [Mutex]
130
138
  def mutex
131
139
  @mutex ||= Mutex.new
132
140
  end
@@ -16,6 +16,7 @@ module Solargraph
16
16
  @block.call(result) unless @block.nil?
17
17
  end
18
18
 
19
+ # @return [void]
19
20
  def send_response
20
21
  # noop
21
22
  end
@@ -402,8 +402,8 @@ module Solargraph
402
402
  repargs = {}
403
403
  workspace.config.reporters.each do |line|
404
404
  if line == 'all!'
405
- Diagnostics.reporters.each do |reporter|
406
- repargs[reporter] ||= []
405
+ Diagnostics.reporters.each do |reporter_name|
406
+ repargs[Diagnostics.reporter(reporter_name)] ||= []
407
407
  end
408
408
  else
409
409
  args = line.split(':').map(&:strip)
@@ -437,17 +437,6 @@ module Solargraph
437
437
  )
438
438
  end
439
439
 
440
- # Get an array of foldable ranges for the specified file.
441
- #
442
- # @deprecated The library should not need to handle folding ranges. The
443
- # source itself has all the information it needs.
444
- #
445
- # @param filename [String]
446
- # @return [Array<Range>]
447
- def folding_ranges filename
448
- read(filename).folding_ranges
449
- end
450
-
451
440
  # Create a library from a directory.
452
441
  #
453
442
  # @param directory [String] The path to be used for the workspace
@@ -511,7 +500,7 @@ module Solargraph
511
500
 
512
501
  private
513
502
 
514
- # @return [Hash{String => Set<String>}]
503
+ # @return [Hash{String => Array<String>}]
515
504
  def source_map_external_require_hash
516
505
  @source_map_external_require_hash ||= {}
517
506
  end
@@ -519,6 +508,7 @@ module Solargraph
519
508
  # @param source_map [SourceMap]
520
509
  # @return [void]
521
510
  def find_external_requires source_map
511
+ # @type [Set<String>]
522
512
  new_set = source_map.requires.map(&:name).to_set
523
513
  # return if new_set == source_map_external_require_hash[source_map.filename]
524
514
  _filenames = nil
@@ -621,6 +611,7 @@ module Solargraph
621
611
  end
622
612
  end
623
613
 
614
+ # @return [Array<Gem::Specification>]
624
615
  def cacheable_specs
625
616
  cacheable = api_map.uncached_yard_gemspecs +
626
617
  api_map.uncached_rbs_collection_gemspecs -
@@ -631,6 +622,7 @@ module Solargraph
631
622
  queued_gemspec_cache
632
623
  end
633
624
 
625
+ # @return [Array<Gem::Specification>]
634
626
  def queued_gemspec_cache
635
627
  @queued_gemspec_cache ||= []
636
628
  end
@@ -672,13 +664,14 @@ module Solargraph
672
664
  @total = nil
673
665
  end
674
666
 
667
+ # @return [void]
675
668
  def sync_catalog
676
669
  return if @sync_count == 0
677
670
 
678
671
  mutex.synchronize do
679
672
  logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
680
- api_map.catalog bench
681
673
  source_map_hash.values.each { |map| find_external_requires(map) }
674
+ api_map.catalog bench
682
675
  logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
683
676
  logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
684
677
  logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
@@ -25,6 +25,7 @@ module Solargraph
25
25
  [filename, range]
26
26
  end
27
27
 
28
+ # @param other [self]
28
29
  def <=>(other)
29
30
  return nil unless other.is_a?(Location)
30
31
  if filename == other.filename
@@ -60,6 +61,7 @@ module Solargraph
60
61
  end
61
62
 
62
63
  # @param node [Parser::AST::Node, nil]
64
+ # @return [Location, nil]
63
65
  def self.from_node(node)
64
66
  return nil if node.nil? || node.loc.nil?
65
67
  range = Range.from_node(node)
@@ -11,8 +11,17 @@ module Solargraph
11
11
  'info' => Logger::INFO,
12
12
  'debug' => Logger::DEBUG
13
13
  }
14
-
15
- @@logger = Logger.new(STDERR, level: DEFAULT_LOG_LEVEL)
14
+ configured_level = ENV.fetch('SOLARGRAPH_LOG', nil)
15
+ level = if LOG_LEVELS.keys.include?(configured_level)
16
+ LOG_LEVELS.fetch(configured_level)
17
+ else
18
+ if configured_level
19
+ warn "Invalid value for SOLARGRAPH_LOG: #{configured_level.inspect} - " \
20
+ "valid values are #{LOG_LEVELS.keys}"
21
+ end
22
+ DEFAULT_LOG_LEVEL
23
+ end
24
+ @@logger = Logger.new(STDERR, level: level)
16
25
  # @sg-ignore Fix cvar issue
17
26
  @@logger.formatter = proc do |severity, datetime, progname, msg|
18
27
  "[#{severity}] #{msg}\n"
@@ -27,8 +27,10 @@ module Solargraph
27
27
  end
28
28
 
29
29
  # @param text [String]
30
+ # @sg-ignore https://github.com/lsegal/yard/pull/1615
30
31
  # @return [String]
31
32
  def htmlify text
33
+ # @type [String]
32
34
  YARD::Templates::Helpers::Markup::RDocMarkup.new(text).to_html
33
35
  end
34
36
 
@@ -70,8 +72,10 @@ module Solargraph
70
72
  # @param template [String]
71
73
  # @param layout [Boolean]
72
74
  # @param locals [Hash]
75
+ # @sg-ignore
73
76
  # @return [String]
74
77
  def render template, layout: true, locals: {}
78
+ # @type [String]
75
79
  @render_method.call(template, layout: layout, locals: locals)
76
80
  end
77
81
 
@@ -3,6 +3,13 @@ require 'ripper'
3
3
  module Solargraph
4
4
  module Parser
5
5
  class CommentRipper < Ripper::SexpBuilderPP
6
+ # @!override Ripper::SexpBuilder#on_embdoc_beg
7
+ # @return [Array(Symbol, String, Array)]
8
+ # @!override Ripper::SexpBuilder#on_embdoc
9
+ # @return [Array(Symbol, String, Array)]
10
+ # @!override Ripper::SexpBuilder#on_embdoc_end
11
+ # @return [Array(Symbol, String, Array)]
12
+
6
13
  # @param src [String]
7
14
  # @param filename [String]
8
15
  # @param lineno [Integer]
@@ -51,7 +58,7 @@ module Solargraph
51
58
  result
52
59
  end
53
60
 
54
- # @return [Hash{Integer => String}]
61
+ # @return [Hash{Integer => Solargraph::Parser::Snippet}]
55
62
  def parse
56
63
  @comments = {}
57
64
  super