solargraph 0.56.2 → 0.58.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +127 -0
  3. data/.github/workflows/plugins.yml +183 -7
  4. data/.github/workflows/rspec.yml +55 -5
  5. data/.github/workflows/typecheck.yml +6 -3
  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 +1279 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +69 -0
  13. data/README.md +8 -4
  14. data/Rakefile +125 -13
  15. data/bin/solargraph +8 -5
  16. data/lib/solargraph/api_map/cache.rb +3 -2
  17. data/lib/solargraph/api_map/constants.rb +279 -0
  18. data/lib/solargraph/api_map/index.rb +49 -31
  19. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  20. data/lib/solargraph/api_map/store.rb +144 -26
  21. data/lib/solargraph/api_map.rb +217 -245
  22. data/lib/solargraph/bench.rb +1 -0
  23. data/lib/solargraph/complex_type/type_methods.rb +6 -0
  24. data/lib/solargraph/complex_type/unique_type.rb +19 -12
  25. data/lib/solargraph/complex_type.rb +24 -3
  26. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  27. data/lib/solargraph/convention/base.rb +17 -0
  28. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -0
  29. data/lib/solargraph/convention/data_definition/data_definition_node.rb +4 -2
  30. data/lib/solargraph/convention/data_definition.rb +2 -1
  31. data/lib/solargraph/convention/gemspec.rb +1 -1
  32. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
  33. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +3 -1
  34. data/lib/solargraph/convention/struct_definition.rb +36 -13
  35. data/lib/solargraph/convention.rb +31 -2
  36. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  38. data/lib/solargraph/doc_map.rb +44 -13
  39. data/lib/solargraph/environ.rb +9 -2
  40. data/lib/solargraph/equality.rb +1 -0
  41. data/lib/solargraph/gem_pins.rb +21 -11
  42. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  43. data/lib/solargraph/language_server/host/message_worker.rb +3 -0
  44. data/lib/solargraph/language_server/host.rb +12 -5
  45. data/lib/solargraph/language_server/message/base.rb +2 -1
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
  47. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/text_document/formatting.rb +19 -2
  49. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  50. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  51. data/lib/solargraph/language_server/progress.rb +8 -0
  52. data/lib/solargraph/language_server/request.rb +4 -1
  53. data/lib/solargraph/library.rb +11 -18
  54. data/lib/solargraph/location.rb +3 -0
  55. data/lib/solargraph/logging.rb +11 -2
  56. data/lib/solargraph/page.rb +3 -0
  57. data/lib/solargraph/parser/comment_ripper.rb +8 -1
  58. data/lib/solargraph/parser/flow_sensitive_typing.rb +33 -5
  59. data/lib/solargraph/parser/node_processor/base.rb +1 -1
  60. data/lib/solargraph/parser/node_processor.rb +6 -2
  61. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -13
  62. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  63. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
  64. data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -16
  65. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +1 -0
  66. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
  67. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
  68. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -0
  69. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +64 -8
  70. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +12 -3
  71. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +36 -16
  72. data/lib/solargraph/parser/region.rb +3 -0
  73. data/lib/solargraph/parser/snippet.rb +2 -0
  74. data/lib/solargraph/pin/base.rb +77 -14
  75. data/lib/solargraph/pin/base_variable.rb +6 -5
  76. data/lib/solargraph/pin/block.rb +3 -2
  77. data/lib/solargraph/pin/callable.rb +14 -1
  78. data/lib/solargraph/pin/closure.rb +5 -7
  79. data/lib/solargraph/pin/common.rb +6 -2
  80. data/lib/solargraph/pin/constant.rb +2 -0
  81. data/lib/solargraph/pin/local_variable.rb +1 -2
  82. data/lib/solargraph/pin/method.rb +28 -9
  83. data/lib/solargraph/pin/method_alias.rb +3 -0
  84. data/lib/solargraph/pin/parameter.rb +24 -10
  85. data/lib/solargraph/pin/proxy_type.rb +5 -1
  86. data/lib/solargraph/pin/reference/override.rb +15 -1
  87. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  88. data/lib/solargraph/pin/reference.rb +17 -0
  89. data/lib/solargraph/pin/search.rb +6 -1
  90. data/lib/solargraph/pin/signature.rb +2 -0
  91. data/lib/solargraph/pin/symbol.rb +5 -0
  92. data/lib/solargraph/pin_cache.rb +64 -4
  93. data/lib/solargraph/position.rb +3 -0
  94. data/lib/solargraph/range.rb +5 -0
  95. data/lib/solargraph/rbs_map/conversions.rb +29 -6
  96. data/lib/solargraph/rbs_map/core_fills.rb +18 -0
  97. data/lib/solargraph/rbs_map/core_map.rb +14 -7
  98. data/lib/solargraph/rbs_map.rb +14 -1
  99. data/lib/solargraph/shell.rb +85 -1
  100. data/lib/solargraph/source/chain/call.rb +7 -3
  101. data/lib/solargraph/source/chain/constant.rb +3 -66
  102. data/lib/solargraph/source/chain/if.rb +1 -1
  103. data/lib/solargraph/source/chain/link.rb +11 -2
  104. data/lib/solargraph/source/chain/or.rb +1 -1
  105. data/lib/solargraph/source/chain.rb +11 -2
  106. data/lib/solargraph/source/change.rb +2 -2
  107. data/lib/solargraph/source/cursor.rb +2 -3
  108. data/lib/solargraph/source/source_chainer.rb +1 -1
  109. data/lib/solargraph/source.rb +6 -3
  110. data/lib/solargraph/source_map/clip.rb +18 -26
  111. data/lib/solargraph/source_map/data.rb +4 -0
  112. data/lib/solargraph/source_map/mapper.rb +2 -2
  113. data/lib/solargraph/source_map.rb +28 -16
  114. data/lib/solargraph/type_checker/param_def.rb +2 -0
  115. data/lib/solargraph/type_checker/rules.rb +30 -8
  116. data/lib/solargraph/type_checker.rb +301 -186
  117. data/lib/solargraph/version.rb +1 -1
  118. data/lib/solargraph/workspace/config.rb +21 -5
  119. data/lib/solargraph/workspace/require_paths.rb +97 -0
  120. data/lib/solargraph/workspace.rb +30 -67
  121. data/lib/solargraph/yard_map/mapper/to_method.rb +4 -3
  122. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  123. data/lib/solargraph/yard_map/to_method.rb +2 -1
  124. data/lib/solargraph/yardoc.rb +39 -3
  125. data/lib/solargraph.rb +2 -0
  126. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  127. data/rbs/fills/open3/0/open3.rbs +172 -0
  128. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  129. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  130. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  131. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  132. data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +2 -3
  133. data/rbs_collection.yaml +4 -4
  134. data/sig/shims/ast/0/node.rbs +5 -0
  135. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  136. data/sig/shims/ast/2.4/ast.rbs +73 -0
  137. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  138. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  139. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  140. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  141. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  142. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  143. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  144. data/solargraph.gemspec +26 -5
  145. metadata +181 -13
  146. data/lib/.rubocop.yml +0 -22
  147. data/lib/solargraph/parser/node_methods.rb +0 -97
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.56.2'
4
+ VERSION = '0.58.0'
5
5
  end
@@ -14,8 +14,8 @@ module Solargraph
14
14
  # @return [String]
15
15
  attr_reader :directory
16
16
 
17
- # @todo To make this strongly typed we'll need a record syntax
18
- # @return [Hash{String => Array, Hash, Integer, nil}]
17
+ # @todo To make JSON strongly typed we'll need a record syntax
18
+ # @return [Hash{String => undefined, nil}]
19
19
  attr_reader :raw_data
20
20
 
21
21
  # @param directory [String]
@@ -63,6 +63,7 @@ module Solargraph
63
63
  # namespace. It's typically used to identify available DSLs.
64
64
  #
65
65
  # @return [Array<String>]
66
+ # @sg-ignore Need to validate config
66
67
  def domains
67
68
  raw_data['domains']
68
69
  end
@@ -70,6 +71,7 @@ module Solargraph
70
71
  # An array of required paths to add to the workspace.
71
72
  #
72
73
  # @return [Array<String>]
74
+ # @sg-ignore Need to validate config
73
75
  def required
74
76
  raw_data['require']
75
77
  end
@@ -83,6 +85,7 @@ module Solargraph
83
85
 
84
86
  # An array of reporters to use for diagnostics.
85
87
  #
88
+ # @sg-ignore Need to validate config
86
89
  # @return [Array<String>]
87
90
  def reporters
88
91
  raw_data['reporters']
@@ -90,7 +93,7 @@ module Solargraph
90
93
 
91
94
  # A hash of options supported by the formatter
92
95
  #
93
- # @sg-ignore pending https://github.com/castwide/solargraph/pull/905
96
+ # @sg-ignore Need to validate config
94
97
  # @return [Hash]
95
98
  def formatter
96
99
  raw_data['formatter']
@@ -98,6 +101,7 @@ module Solargraph
98
101
 
99
102
  # An array of plugins to require.
100
103
  #
104
+ # @sg-ignore Need to validate config
101
105
  # @return [Array<String>]
102
106
  def plugins
103
107
  raw_data['plugins']
@@ -105,12 +109,21 @@ module Solargraph
105
109
 
106
110
  # The maximum number of files to parse from the workspace.
107
111
  #
108
- # @sg-ignore pending https://github.com/castwide/solargraph/pull/905
112
+ # @sg-ignore Need to validate config
109
113
  # @return [Integer]
110
114
  def max_files
111
115
  raw_data['max_files']
112
116
  end
113
117
 
118
+ # @return [Hash{Symbol => Symbol}]
119
+ def type_checker_rules
120
+ # @type [Hash{String => String}]
121
+ raw_rules = raw_data.fetch('type_checker', {}).fetch('rules', {})
122
+ raw_rules.to_h do |k, v|
123
+ [k.to_sym, v.to_sym]
124
+ end
125
+ end
126
+
114
127
  private
115
128
 
116
129
  # @return [String]
@@ -125,7 +138,7 @@ module Solargraph
125
138
  File.join(@directory, '.solargraph.yml')
126
139
  end
127
140
 
128
- # @return [Hash{String => Array<undefined>, Hash{String => undefined}, Integer}]
141
+ # @return [Hash{String => undefined}]
129
142
  def config_data
130
143
  workspace_config = read_config(workspace_config_path)
131
144
  global_config = read_config(global_config_path)
@@ -164,6 +177,9 @@ module Solargraph
164
177
  'extra_args' =>[]
165
178
  }
166
179
  },
180
+ 'type_checker' => {
181
+ 'rules' => { }
182
+ },
167
183
  'require_paths' => [],
168
184
  'plugins' => [],
169
185
  'max_files' => MAX_FILES
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Solargraph
6
+ # A workspace consists of the files in a project's directory and the
7
+ # project's configuration. It provides a Source for each file to be used
8
+ # in an associated Library or ApiMap.
9
+ #
10
+ class Workspace
11
+ # Manages determining which gemspecs are available in a workspace
12
+ class RequirePaths
13
+ attr_reader :directory, :config
14
+
15
+ # @param directory [String, nil]
16
+ # @param config [Config, nil]
17
+ def initialize directory, config
18
+ @directory = directory
19
+ @config = config
20
+ end
21
+
22
+ # Generate require paths from gemspecs if they exist or assume the default
23
+ # lib directory.
24
+ #
25
+ # @return [Array<String>]
26
+ def generate
27
+ result = require_paths_from_gemspec_files
28
+ return configured_require_paths if result.empty?
29
+ result.concat(config.require_paths.map { |p| File.join(directory, p) }) if config
30
+ result
31
+ end
32
+
33
+ private
34
+
35
+ # @return [Array<String>]
36
+ def require_paths_from_gemspec_files
37
+ results = []
38
+ gemspec_file_paths.each do |gemspec_file_path|
39
+ results.concat require_path_from_gemspec_file(gemspec_file_path)
40
+ end
41
+ results
42
+ end
43
+
44
+ # Get an array of all gemspec files in the workspace.
45
+ #
46
+ # @return [Array<String>]
47
+ def gemspec_file_paths
48
+ return [] if directory.nil?
49
+ @gemspec_file_paths ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
50
+ config.nil? || config.allow?(gs)
51
+ end
52
+ end
53
+
54
+ # Get additional require paths defined in the configuration.
55
+ #
56
+ # @return [Array<String>]
57
+ def configured_require_paths
58
+ return ['lib'] unless directory
59
+ return [File.join(directory, 'lib')] if !config || config.require_paths.empty?
60
+ config.require_paths.map { |p| File.join(directory, p) }
61
+ end
62
+
63
+ # Generate require paths from gemspecs if they exist or assume the default
64
+ # lib directory.
65
+ #
66
+ # @param gemspec_file_path [String]
67
+ # @return [Array<String>]
68
+ def require_path_from_gemspec_file gemspec_file_path
69
+ base = File.dirname(gemspec_file_path)
70
+ # HACK: Evaluating gemspec files violates the goal of not running
71
+ # workspace code, but this is how Gem::Specification.load does it
72
+ # anyway.
73
+ cmd = ['ruby', '-e',
74
+ "require 'rubygems'; " \
75
+ "require 'json'; " \
76
+ "spec = eval(File.read('#{gemspec_file_path}'), TOPLEVEL_BINDING, '#{gemspec_file_path}'); " \
77
+ 'return unless Gem::Specification === spec; ' \
78
+ 'puts({name: spec.name, paths: spec.require_paths}.to_json)']
79
+ o, e, s = Open3.capture3(*cmd)
80
+ if s.success?
81
+ begin
82
+ hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
83
+ return [] if hash.empty?
84
+ hash['paths'].map { |path| File.join(base, path) }
85
+ rescue StandardError => e
86
+ Solargraph.logger.warn "Error reading #{gemspec_file_path}: [#{e.class}] #{e.message}"
87
+ []
88
+ end
89
+ else
90
+ Solargraph.logger.warn "Error reading #{gemspec_file_path}"
91
+ Solargraph.logger.warn e
92
+ []
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -10,37 +10,52 @@ module Solargraph
10
10
  #
11
11
  class Workspace
12
12
  autoload :Config, 'solargraph/workspace/config'
13
+ autoload :RequirePaths, 'solargraph/workspace/require_paths'
13
14
 
14
15
  # @return [String]
15
16
  attr_reader :directory
16
17
 
17
- # The require paths associated with the workspace.
18
- #
19
- # @return [Array<String>]
20
- attr_reader :require_paths
21
-
22
18
  # @return [Array<String>]
23
19
  attr_reader :gemnames
24
20
  alias source_gems gemnames
25
21
 
26
- # @param directory [String]
22
+ # @param directory [String] TODO: Remove '' and '*' special cases
27
23
  # @param config [Config, nil]
28
24
  # @param server [Hash]
29
25
  def initialize directory = '', config = nil, server = {}
30
- @directory = directory
26
+ raise ArgumentError, 'directory must be a String' unless directory.is_a?(String)
27
+
28
+ @directory = if ['*', ''].include?(directory)
29
+ directory
30
+ else
31
+ File.absolute_path(directory)
32
+ end
31
33
  @config = config
32
34
  @server = server
33
35
  load_sources
34
36
  @gemnames = []
35
- @require_paths = generate_require_paths
36
37
  require_plugins
37
38
  end
38
39
 
40
+ # The require paths associated with the workspace.
41
+ #
42
+ # @return [Array<String>]
43
+ def require_paths
44
+ # @todo are the semantics of '*' the same as '', meaning 'don't send back any require paths'?
45
+ @require_paths ||= RequirePaths.new(directory_or_nil, config).generate
46
+ end
47
+
39
48
  # @return [Solargraph::Workspace::Config]
40
49
  def config
41
50
  @config ||= Solargraph::Workspace::Config.new(directory)
42
51
  end
43
52
 
53
+ # @param level [Symbol]
54
+ # @return [TypeChecker::Rules]
55
+ def rules(level)
56
+ @rules ||= TypeChecker::Rules.new(level, config.type_checker_rules)
57
+ end
58
+
44
59
  # Merge the source. A merge will update the existing source for the file
45
60
  # or add it to the sources if the workspace is configured to include it.
46
61
  # The source is ignored if the configuration excludes it.
@@ -111,28 +126,12 @@ module Solargraph
111
126
  false
112
127
  end
113
128
 
114
- # True if the workspace contains at least one gemspec file.
115
- #
116
- # @return [Boolean]
117
- def gemspec?
118
- !gemspecs.empty?
119
- end
120
-
121
- # Get an array of all gemspec files in the workspace.
122
- #
123
- # @return [Array<String>]
124
- def gemspecs
125
- return [] if directory.empty? || directory == '*'
126
- @gemspecs ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
127
- config.allow? gs
128
- end
129
- end
130
-
131
129
  # @return [String, nil]
132
130
  def rbs_collection_path
133
131
  @gem_rbs_collection ||= read_rbs_collection_path
134
132
  end
135
133
 
134
+ # @return [String, nil]
136
135
  def rbs_collection_config_path
137
136
  @rbs_collection_config_path ||= begin
138
137
  unless directory.empty? || directory == '*'
@@ -155,6 +154,12 @@ module Solargraph
155
154
  server['commandPath'] || 'solargraph'
156
155
  end
157
156
 
157
+ # @return [String, nil]
158
+ def directory_or_nil
159
+ return nil if directory.empty? || directory == '*'
160
+ directory
161
+ end
162
+
158
163
  # True if the workspace has a root Gemfile.
159
164
  #
160
165
  # @todo Handle projects with custom Bundler/Gemfile setups (see DocMap#gemspecs_required_from_bundler)
@@ -192,48 +197,6 @@ module Solargraph
192
197
  end
193
198
  end
194
199
 
195
- # Generate require paths from gemspecs if they exist or assume the default
196
- # lib directory.
197
- #
198
- # @return [Array<String>]
199
- def generate_require_paths
200
- return configured_require_paths unless gemspec?
201
- result = []
202
- gemspecs.each do |file|
203
- base = File.dirname(file)
204
- # HACK: Evaluating gemspec files violates the goal of not running
205
- # workspace code, but this is how Gem::Specification.load does it
206
- # anyway.
207
- cmd = ['ruby', '-e', "require 'rubygems'; require 'json'; spec = eval(File.read('#{file}'), TOPLEVEL_BINDING, '#{file}'); return unless Gem::Specification === spec; puts({name: spec.name, paths: spec.require_paths}.to_json)"]
208
- o, e, s = Open3.capture3(*cmd)
209
- if s.success?
210
- begin
211
- hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
212
- next if hash.empty?
213
- @gemnames.push hash['name']
214
- result.concat(hash['paths'].map { |path| File.join(base, path) })
215
- rescue StandardError => e
216
- Solargraph.logger.warn "Error reading #{file}: [#{e.class}] #{e.message}"
217
- end
218
- else
219
- Solargraph.logger.warn "Error reading #{file}"
220
- Solargraph.logger.warn e
221
- end
222
- end
223
- result.concat(config.require_paths.map { |p| File.join(directory, p) })
224
- result.push File.join(directory, 'lib') if result.empty?
225
- result
226
- end
227
-
228
- # Get additional require paths defined in the configuration.
229
- #
230
- # @return [Array<String>]
231
- def configured_require_paths
232
- return ['lib'] if directory.empty?
233
- return [File.join(directory, 'lib')] if config.require_paths.empty?
234
- config.require_paths.map { |p| File.join(directory, p) }
235
- end
236
-
237
200
  # @return [void]
238
201
  def require_plugins
239
202
  config.plugins.each do |plugin|
@@ -11,7 +11,7 @@ module Solargraph
11
11
  ["Rails::Engine", :class, "find_root_with_flag"] => :public
12
12
  }
13
13
 
14
- # @param code_object [YARD::CodeObjects::Base]
14
+ # @param code_object [YARD::CodeObjects::MethodObject]
15
15
  # @param name [String, nil]
16
16
  # @param scope [Symbol, nil]
17
17
  # @param visibility [Symbol, nil]
@@ -27,8 +27,8 @@ module Solargraph
27
27
  final_scope = scope || code_object.scope
28
28
  override_key = [closure.path, final_scope, name]
29
29
  final_visibility = VISIBILITY_OVERRIDE[override_key]
30
- final_visibility ||= VISIBILITY_OVERRIDE[override_key[0..-2]]
31
- final_visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(name)
30
+ final_visibility ||= VISIBILITY_OVERRIDE[[closure.path, final_scope]]
31
+ final_visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(name.to_sym)
32
32
  final_visibility ||= visibility
33
33
  final_visibility ||= :private if code_object.module_function? && final_scope == :instance
34
34
  final_visibility ||= :public if code_object.module_function? && final_scope == :class
@@ -85,6 +85,7 @@ module Solargraph
85
85
  # HACK: Skip `nil` and `self` parameters that are sometimes emitted
86
86
  # for methods defined in C
87
87
  # See https://github.com/castwide/solargraph/issues/345
88
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
88
89
  code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
89
90
  Solargraph::Pin::Parameter.new(
90
91
  location: location,
@@ -21,6 +21,7 @@ module Solargraph
21
21
  type: code_object.is_a?(YARD::CodeObjects::ClassObject) ? :class : :module,
22
22
  visibility: code_object.visibility,
23
23
  closure: closure,
24
+ gates: closure.gates,
24
25
  source: :yardoc,
25
26
  )
26
27
  end
@@ -15,6 +15,7 @@ module Solargraph
15
15
  # HACK: Skip `nil` and `self` parameters that are sometimes emitted
16
16
  # for methods defined in C
17
17
  # See https://github.com/castwide/solargraph/issues/345
18
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
18
19
  code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
19
20
  Solargraph::Pin::Parameter.new(
20
21
  location: location,
@@ -57,7 +58,7 @@ module Solargraph
57
58
 
58
59
  include Helpers
59
60
 
60
- # @param code_object [YARD::CodeObjects::Base]
61
+ # @param code_object [YARD::CodeObjects::MethodObject]
61
62
  # @param name [String, nil]
62
63
  # @param scope [Symbol, nil]
63
64
  # @param visibility [Symbol, nil]
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'open3'
4
+
3
5
  module Solargraph
4
6
  # Methods for caching and loading YARD documentation for gems.
5
7
  #
@@ -9,15 +11,31 @@ module Solargraph
9
11
  # Build and cache a gem's yardoc and return the path. If the cache already
10
12
  # exists, do nothing and return the path.
11
13
  #
14
+ # @param yard_plugins [Array<String>] The names of YARD plugins to use.
12
15
  # @param gemspec [Gem::Specification]
13
16
  # @return [String] The path to the cached yardoc.
14
- def cache(gemspec)
17
+ def cache(yard_plugins, gemspec)
15
18
  path = PinCache.yardoc_path gemspec
16
19
  return path if cached?(gemspec)
17
20
 
21
+ unless Dir.exist? gemspec.gem_dir
22
+ # Can happen in at least some (old?) RubyGems versions when we
23
+ # have a gemspec describing a standard library like bundler.
24
+ #
25
+ # https://github.com/apiology/solargraph/actions/runs/17650140201/job/50158676842?pr=10
26
+ Solargraph.logger.info { "Bad info from gemspec - #{gemspec.gem_dir} does not exist" }
27
+ return path
28
+ end
29
+
18
30
  Solargraph.logger.info "Caching yardoc for #{gemspec.name} #{gemspec.version}"
19
- Dir.chdir gemspec.gem_dir do
20
- `yardoc --db #{path} --no-output --plugin solargraph`
31
+ cmd = "yardoc --db #{path} --no-output --plugin solargraph"
32
+ yard_plugins.each { |plugin| cmd << " --plugin #{plugin}" }
33
+ Solargraph.logger.debug { "Running: #{cmd}" }
34
+ # @todo set these up to run in parallel
35
+ stdout_and_stderr_str, status = Open3.capture2e(current_bundle_env_tweaks, cmd, chdir: gemspec.gem_dir)
36
+ unless status.success?
37
+ Solargraph.logger.warn { "YARD failed running #{cmd.inspect} in #{gemspec.gem_dir}" }
38
+ Solargraph.logger.info stdout_and_stderr_str
21
39
  end
22
40
  path
23
41
  end
@@ -32,6 +50,7 @@ module Solargraph
32
50
 
33
51
  # True if another process is currently building the yardoc cache.
34
52
  #
53
+ # @param gemspec [Gem::Specification]
35
54
  def processing?(gemspec)
36
55
  yardoc = File.join(PinCache.yardoc_path(gemspec), 'processing')
37
56
  File.exist?(yardoc)
@@ -47,5 +66,22 @@ module Solargraph
47
66
  YARD::Registry.load! PinCache.yardoc_path gemspec
48
67
  YARD::Registry.all
49
68
  end
69
+
70
+ # If the BUNDLE_GEMFILE environment variable is set, we need to
71
+ # make sure it's an absolute path, as we'll be changing
72
+ # directories.
73
+ #
74
+ # 'bundle exec' sets an absolute path here, but at least the
75
+ # overcommit gem does not, breaking on-the-fly documention with a
76
+ # spawned yardoc command from our current bundle
77
+ #
78
+ # @return [Hash{String => String}] a hash of environment variables to override
79
+ def current_bundle_env_tweaks
80
+ tweaks = {}
81
+ if ENV['BUNDLE_GEMFILE'] && !ENV['BUNDLE_GEMFILE'].empty?
82
+ tweaks['BUNDLE_GEMFILE'] = File.expand_path(ENV['BUNDLE_GEMFILE'])
83
+ end
84
+ tweaks
85
+ end
50
86
  end
51
87
  end
data/lib/solargraph.rb CHANGED
@@ -53,6 +53,8 @@ module Solargraph
53
53
  dir = File.dirname(__FILE__)
54
54
  VIEWS_PATH = File.join(dir, 'solargraph', 'views')
55
55
 
56
+ CHDIR_MUTEX = Mutex.new
57
+
56
58
  # @param type [Symbol] Type of assert.
57
59
  def self.asserts_on?(type)
58
60
  if ENV['SOLARGRAPH_ASSERTS'].nil? || ENV['SOLARGRAPH_ASSERTS'].empty?