solargraph 0.58.2 → 0.59.0.dev.1
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.
- checksums.yaml +4 -4
- data/.envrc +3 -0
- data/.github/workflows/linting.yml +4 -5
- data/.github/workflows/plugins.yml +40 -36
- data/.github/workflows/rspec.yml +45 -13
- data/.github/workflows/typecheck.yml +2 -2
- data/.gitignore +0 -1
- data/.rubocop_todo.yml +27 -49
- data/CHANGELOG.md +1 -7
- data/README.md +3 -3
- data/Rakefile +1 -0
- data/lib/solargraph/api_map/cache.rb +3 -3
- data/lib/solargraph/api_map/constants.rb +13 -3
- data/lib/solargraph/api_map/index.rb +22 -11
- data/lib/solargraph/api_map/source_to_yard.rb +13 -1
- data/lib/solargraph/api_map/store.rb +11 -8
- data/lib/solargraph/api_map.rb +105 -50
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +16 -2
- data/lib/solargraph/complex_type/unique_type.rb +170 -20
- data/lib/solargraph/complex_type.rb +119 -14
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
- data/lib/solargraph/convention/data_definition.rb +4 -1
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition.rb +5 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
- data/lib/solargraph/diagnostics/type_check.rb +1 -0
- data/lib/solargraph/doc_map.rb +134 -373
- data/lib/solargraph/equality.rb +1 -1
- data/lib/solargraph/gem_pins.rb +14 -15
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
- data/lib/solargraph/language_server/host/dispatch.rb +1 -0
- data/lib/solargraph/language_server/host/message_worker.rb +2 -1
- data/lib/solargraph/language_server/host/sources.rb +1 -0
- data/lib/solargraph/language_server/host.rb +6 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -7
- data/lib/solargraph/language_server/message/extended/document.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/completion.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +2 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -0
- data/lib/solargraph/library.rb +59 -13
- data/lib/solargraph/location.rb +9 -4
- data/lib/solargraph/logging.rb +21 -1
- data/lib/solargraph/parser/comment_ripper.rb +7 -0
- data/lib/solargraph/parser/flow_sensitive_typing.rb +330 -102
- data/lib/solargraph/parser/node_processor/base.rb +32 -2
- data/lib/solargraph/parser/node_processor.rb +7 -6
- data/lib/solargraph/parser/parser_gem/class_methods.rb +28 -10
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +31 -6
- data/lib/solargraph/parser/parser_gem/node_methods.rb +27 -7
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -11
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +7 -0
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +3 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +12 -7
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +5 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
- data/lib/solargraph/parser/region.rb +9 -3
- data/lib/solargraph/parser/snippet.rb +1 -1
- data/lib/solargraph/pin/base.rb +53 -21
- data/lib/solargraph/pin/base_variable.rb +312 -20
- data/lib/solargraph/pin/block.rb +26 -4
- data/lib/solargraph/pin/breakable.rb +5 -1
- data/lib/solargraph/pin/callable.rb +50 -3
- data/lib/solargraph/pin/closure.rb +2 -6
- data/lib/solargraph/pin/common.rb +20 -5
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/conversions.rb +2 -1
- data/lib/solargraph/pin/delegated_method.rb +15 -4
- data/lib/solargraph/pin/documenting.rb +1 -0
- data/lib/solargraph/pin/instance_variable.rb +5 -1
- data/lib/solargraph/pin/keyword.rb +0 -4
- data/lib/solargraph/pin/local_variable.rb +13 -57
- data/lib/solargraph/pin/method.rb +90 -42
- data/lib/solargraph/pin/method_alias.rb +8 -0
- data/lib/solargraph/pin/namespace.rb +7 -1
- data/lib/solargraph/pin/parameter.rb +76 -13
- data/lib/solargraph/pin/proxy_type.rb +2 -1
- data/lib/solargraph/pin/reference/override.rb +1 -1
- data/lib/solargraph/pin/reference/superclass.rb +2 -0
- data/lib/solargraph/pin/reference.rb +2 -0
- data/lib/solargraph/pin/search.rb +1 -0
- data/lib/solargraph/pin/signature.rb +8 -0
- data/lib/solargraph/pin/symbol.rb +1 -1
- data/lib/solargraph/pin/until.rb +1 -1
- data/lib/solargraph/pin/while.rb +1 -1
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin_cache.rb +477 -57
- data/lib/solargraph/position.rb +12 -26
- data/lib/solargraph/range.rb +6 -6
- data/lib/solargraph/rbs_map/conversions.rb +33 -10
- data/lib/solargraph/rbs_map/core_map.rb +24 -17
- data/lib/solargraph/rbs_map/stdlib_map.rb +34 -5
- data/lib/solargraph/rbs_map.rb +74 -20
- data/lib/solargraph/shell.rb +73 -28
- data/lib/solargraph/source/chain/call.rb +52 -17
- data/lib/solargraph/source/chain/constant.rb +2 -0
- data/lib/solargraph/source/chain/hash.rb +1 -0
- data/lib/solargraph/source/chain/if.rb +1 -0
- data/lib/solargraph/source/chain/instance_variable.rb +22 -1
- data/lib/solargraph/source/chain/literal.rb +5 -0
- data/lib/solargraph/source/chain/or.rb +9 -1
- data/lib/solargraph/source/chain.rb +25 -22
- data/lib/solargraph/source/change.rb +9 -2
- data/lib/solargraph/source/cursor.rb +7 -1
- data/lib/solargraph/source/source_chainer.rb +13 -3
- data/lib/solargraph/source/updater.rb +4 -0
- data/lib/solargraph/source.rb +33 -7
- data/lib/solargraph/source_map/clip.rb +13 -2
- data/lib/solargraph/source_map/data.rb +4 -1
- data/lib/solargraph/source_map/mapper.rb +24 -1
- data/lib/solargraph/source_map.rb +14 -6
- data/lib/solargraph/type_checker/problem.rb +3 -1
- data/lib/solargraph/type_checker/rules.rb +75 -2
- data/lib/solargraph/type_checker.rb +111 -30
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +3 -1
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +1 -0
- data/lib/solargraph/workspace.rb +158 -16
- data/lib/solargraph/yard_map/helpers.rb +2 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +5 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
- data/lib/solargraph/yard_map/mapper.rb +5 -0
- data/lib/solargraph/yardoc.rb +33 -23
- data/lib/solargraph.rb +24 -3
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +1 -1
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/solargraph.gemspec +2 -1
- metadata +12 -7
- data/lib/solargraph/type_checker/checks.rb +0 -124
- data/lib/solargraph/type_checker/param_def.rb +0 -37
- data/lib/solargraph/yard_map/to_method.rb +0 -89
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler'
|
|
5
|
+
|
|
6
|
+
module Solargraph
|
|
7
|
+
class Workspace
|
|
8
|
+
# Manages determining which gemspecs are available in a workspace
|
|
9
|
+
class Gemspecs
|
|
10
|
+
include Logging
|
|
11
|
+
|
|
12
|
+
attr_reader :directory, :preferences
|
|
13
|
+
|
|
14
|
+
# @param directory [String, nil] If nil, assume no bundle is present
|
|
15
|
+
# @param preferences [Array<Gem::Specification>]
|
|
16
|
+
def initialize directory, preferences: []
|
|
17
|
+
# @todo an issue with both external bundles and the potential
|
|
18
|
+
# preferences feature is that bundler gives you a 'clean'
|
|
19
|
+
# rubygems environment with only the specified versions
|
|
20
|
+
# installed. Possible alternatives:
|
|
21
|
+
#
|
|
22
|
+
# *) prompt the user to run solargraph outside of bundler
|
|
23
|
+
# and treat all bundles as external
|
|
24
|
+
# *) reinstall the needed gems dynamically each time
|
|
25
|
+
# *) manipulate the rubygems/bundler environment
|
|
26
|
+
@directory = directory && File.absolute_path(directory)
|
|
27
|
+
# @todo implement preferences as a config-exposed feature
|
|
28
|
+
@preferences = preferences
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Take the path given to a 'require' statement in a source file
|
|
32
|
+
# and return the Gem::Specifications which will be brought into
|
|
33
|
+
# scope with it, so we can load pins for them.
|
|
34
|
+
#
|
|
35
|
+
# @param require [String] The string sent to 'require' in the code to resolve, e.g. 'rails', 'bundler/require'
|
|
36
|
+
# @return [::Array<Gem::Specification>, nil]
|
|
37
|
+
def resolve_require require
|
|
38
|
+
return nil if require.empty?
|
|
39
|
+
|
|
40
|
+
# This is added in the parser when it sees 'Bundler.require' -
|
|
41
|
+
# see https://bundler.io/guides/bundler_setup.html '
|
|
42
|
+
#
|
|
43
|
+
# @todo handle different arguments to Bundler.require
|
|
44
|
+
return auto_required_gemspecs_from_bundler if require == 'bundler/require'
|
|
45
|
+
|
|
46
|
+
# Determine gem name based on the require path
|
|
47
|
+
file = "lib/#{require}.rb"
|
|
48
|
+
spec_with_path = Gem::Specification.find_by_path(file)
|
|
49
|
+
|
|
50
|
+
all_gemspecs = all_gemspecs_from_bundle
|
|
51
|
+
|
|
52
|
+
gem_names_to_try = [
|
|
53
|
+
spec_with_path&.name,
|
|
54
|
+
require.tr('/', '-'),
|
|
55
|
+
require.split('/').first
|
|
56
|
+
].compact.uniq
|
|
57
|
+
# @param gem_name [String]
|
|
58
|
+
gem_names_to_try.each do |gem_name|
|
|
59
|
+
# @sg-ignore Unresolved call to == on Boolean
|
|
60
|
+
gemspec = all_gemspecs.find { |gemspec| gemspec.name == gem_name }
|
|
61
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
62
|
+
return [gemspec_or_preference(gemspec)] if gemspec
|
|
63
|
+
|
|
64
|
+
begin
|
|
65
|
+
gemspec = Gem::Specification.find_by_name(gem_name)
|
|
66
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
67
|
+
return [gemspec_or_preference(gemspec)] if gemspec
|
|
68
|
+
rescue Gem::MissingSpecError
|
|
69
|
+
logger.debug do
|
|
70
|
+
"Require path #{require} could not be resolved to a gem via find_by_path or guess of #{gem_name}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# look ourselves just in case this is hanging out somewhere
|
|
75
|
+
# that find_by_path doesn't index
|
|
76
|
+
gemspec = all_gemspecs.find do |spec|
|
|
77
|
+
spec = to_gem_specification(spec) unless spec.respond_to?(:files)
|
|
78
|
+
|
|
79
|
+
# @sg-ignore Translate to something flow sensitive typing understands
|
|
80
|
+
spec&.files&.any? { |gemspec_file| file == gemspec_file }
|
|
81
|
+
end
|
|
82
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
83
|
+
return [gemspec_or_preference(gemspec)] if gemspec
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @param stdlib_name [String]
|
|
90
|
+
#
|
|
91
|
+
# @return [Array<String>]
|
|
92
|
+
def stdlib_dependencies stdlib_name
|
|
93
|
+
deps = RbsMap::StdlibMap.stdlib_dependencies(stdlib_name, nil) || []
|
|
94
|
+
deps.map { |dep| dep['name'] }.compact
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @param name [String]
|
|
98
|
+
# @param version [String, nil]
|
|
99
|
+
# @param out [IO, nil] output stream for logging
|
|
100
|
+
#
|
|
101
|
+
# @return [Gem::Specification, nil]
|
|
102
|
+
def find_gem name, version = nil, out: $stderr
|
|
103
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
104
|
+
specish = all_gemspecs_from_bundle.find { |specish| specish.name == name && specish.version == version }
|
|
105
|
+
return to_gem_specification specish if specish
|
|
106
|
+
|
|
107
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
108
|
+
specish = all_gemspecs_from_bundle.find { |specish| specish.name == name }
|
|
109
|
+
# @sg-ignore flow sensitive typing needs to create separate ranges for postfix if
|
|
110
|
+
return to_gem_specification specish if specish
|
|
111
|
+
|
|
112
|
+
resolve_gem_ignoring_local_bundle name, version, out: out
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @param gemspec [Gem::Specification]
|
|
116
|
+
# @param out[IO, nil] output stream for logging
|
|
117
|
+
#
|
|
118
|
+
# @return [Array<Gem::Specification>]
|
|
119
|
+
def fetch_dependencies gemspec, out: $stderr
|
|
120
|
+
gemspecs = all_gemspecs_from_bundle
|
|
121
|
+
|
|
122
|
+
# @type [Hash{String => Gem::Specification}]
|
|
123
|
+
deps_so_far = {}
|
|
124
|
+
|
|
125
|
+
# @param runtime_dep [Gem::Dependency]
|
|
126
|
+
# @param deps [Hash{String => Gem::Specification}]
|
|
127
|
+
gem_dep_gemspecs = only_runtime_dependencies(gemspec).each_with_object(deps_so_far) do |runtime_dep, deps|
|
|
128
|
+
dep = find_gem(runtime_dep.name, runtime_dep.requirement)
|
|
129
|
+
next unless dep
|
|
130
|
+
|
|
131
|
+
fetch_dependencies(dep, out: out).each { |sub_dep| deps[sub_dep.name] ||= sub_dep }
|
|
132
|
+
|
|
133
|
+
deps[dep.name] ||= dep
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# RBS tracks implicit dependencies, like how the YAML standard
|
|
137
|
+
# library implies pulling in the psych library.
|
|
138
|
+
stdlib_deps = RbsMap::StdlibMap.stdlib_dependencies(gemspec.name, gemspec.version) || []
|
|
139
|
+
stdlib_dep_gemspecs = stdlib_deps.map { |dep| find_gem(dep['name'], dep['version']) }.compact
|
|
140
|
+
(gem_dep_gemspecs.values.compact + stdlib_dep_gemspecs).uniq(&:name)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Returns all gemspecs directly depended on by this workspace's
|
|
144
|
+
# bundle (does not include transitive dependencies).
|
|
145
|
+
#
|
|
146
|
+
# @return [Array<Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification>]
|
|
147
|
+
def all_gemspecs_from_bundle
|
|
148
|
+
return [] unless directory
|
|
149
|
+
|
|
150
|
+
@all_gemspecs_from_bundle ||=
|
|
151
|
+
if in_this_bundle?
|
|
152
|
+
all_gemspecs_from_this_bundle
|
|
153
|
+
else
|
|
154
|
+
all_gemspecs_from_external_bundle
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @return [Hash{Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification => Gem::Specification}]
|
|
159
|
+
def self.gem_specification_cache
|
|
160
|
+
@gem_specification_cache ||= {}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
# @param specish [Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification]
|
|
166
|
+
#
|
|
167
|
+
# @return [Gem::Specification, nil]
|
|
168
|
+
# @sg-ignore flow sensitive typing needs better handling of ||= on lvars
|
|
169
|
+
def to_gem_specification specish
|
|
170
|
+
# print time including milliseconds
|
|
171
|
+
self.class.gem_specification_cache[specish] ||= case specish
|
|
172
|
+
when Gem::Specification
|
|
173
|
+
specish
|
|
174
|
+
when Bundler::LazySpecification
|
|
175
|
+
# materializing didn't work. Let's look in the local
|
|
176
|
+
# rubygems without bundler's help
|
|
177
|
+
resolve_gem_ignoring_local_bundle specish.name,
|
|
178
|
+
specish.version
|
|
179
|
+
when Bundler::StubSpecification
|
|
180
|
+
# turns a Bundler::StubSpecification into a
|
|
181
|
+
# Gem::StubSpecification if we can
|
|
182
|
+
if specish.respond_to?(:stub)
|
|
183
|
+
# @sg-ignore flow sensitive typing ought to be able to handle 'when ClassName'
|
|
184
|
+
to_gem_specification specish.stub
|
|
185
|
+
else
|
|
186
|
+
# A Bundler::StubSpecification is a Bundler::
|
|
187
|
+
# RemoteSpecification which ought to proxy a Gem::
|
|
188
|
+
# Specification
|
|
189
|
+
specish
|
|
190
|
+
end
|
|
191
|
+
# @sg-ignore Unresolved constant Gem::StubSpecification
|
|
192
|
+
when Gem::StubSpecification
|
|
193
|
+
# @sg-ignore flow sensitive typing ought to be able to handle 'when ClassName'
|
|
194
|
+
specish.to_spec
|
|
195
|
+
else
|
|
196
|
+
raise "Unexpected type while resolving gem: #{specish.class}"
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# @param command [String] The expression to evaluate in the external bundle
|
|
201
|
+
# @sg-ignore Need a JSON type
|
|
202
|
+
# @yield [undefined, nil]
|
|
203
|
+
def query_external_bundle command
|
|
204
|
+
Solargraph.with_clean_env do
|
|
205
|
+
cmd = [
|
|
206
|
+
'ruby', '-e',
|
|
207
|
+
"require 'bundler'; require 'json'; Dir.chdir('#{directory}') { puts begin; #{command}; end.to_json }"
|
|
208
|
+
]
|
|
209
|
+
o, e, s = Open3.capture3(*cmd)
|
|
210
|
+
if s.success?
|
|
211
|
+
Solargraph.logger.debug "External bundle: #{o}"
|
|
212
|
+
o && !o.empty? ? JSON.parse(o.split("\n").last) : nil
|
|
213
|
+
else
|
|
214
|
+
Solargraph.logger.warn e
|
|
215
|
+
raise BundleNotFoundError, "Failed to load gems from bundle at #{directory}"
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# @sg-ignore need boolish support for ? methods
|
|
221
|
+
def in_this_bundle?
|
|
222
|
+
Bundler.definition&.lockfile&.to_s&.start_with?(directory)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# @return [Array<Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification>]
|
|
226
|
+
def all_gemspecs_from_this_bundle
|
|
227
|
+
# Find only the gems bundler is now using
|
|
228
|
+
specish_objects = Bundler.definition.locked_gems.specs
|
|
229
|
+
if specish_objects.first.respond_to?(:materialize_for_installation)
|
|
230
|
+
specish_objects = specish_objects.map(&:materialize_for_installation)
|
|
231
|
+
end
|
|
232
|
+
specish_objects.map do |specish|
|
|
233
|
+
if specish.respond_to?(:name) && specish.respond_to?(:version) && specish.respond_to?(:gem_dir)
|
|
234
|
+
# duck type is good enough for outside uses!
|
|
235
|
+
specish
|
|
236
|
+
else
|
|
237
|
+
to_gem_specification(specish)
|
|
238
|
+
end
|
|
239
|
+
end.compact
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# @return [Array<Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification>]
|
|
243
|
+
def auto_required_gemspecs_from_bundler
|
|
244
|
+
return [] unless directory
|
|
245
|
+
|
|
246
|
+
logger.info 'Fetching gemspecs autorequired from Bundler (bundler/require)'
|
|
247
|
+
@auto_required_gemspecs_from_bundler ||=
|
|
248
|
+
if in_this_bundle?
|
|
249
|
+
auto_required_gemspecs_from_this_bundle
|
|
250
|
+
else
|
|
251
|
+
auto_required_gemspecs_from_external_bundle
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# @return [Array<Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification>]
|
|
256
|
+
def auto_required_gemspecs_from_this_bundle
|
|
257
|
+
# Adapted from require() in lib/bundler/runtime.rb
|
|
258
|
+
dep_names = Bundler.definition.dependencies.select do |dep|
|
|
259
|
+
dep.groups.include?(:default) && dep.should_include?
|
|
260
|
+
end.map(&:name)
|
|
261
|
+
|
|
262
|
+
all_gemspecs_from_bundle.select { |gemspec| dep_names.include?(gemspec.name) }
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# @return [Array<Gem::Specification, Bundler::LazySpecification, Bundler::StubSpecification>]
|
|
266
|
+
def auto_required_gemspecs_from_external_bundle
|
|
267
|
+
@auto_required_gemspecs_from_external_bundle ||=
|
|
268
|
+
begin
|
|
269
|
+
logger.info 'Fetching auto-required gemspecs from Bundler (bundler/require)'
|
|
270
|
+
command =
|
|
271
|
+
'Bundler.definition.dependencies' \
|
|
272
|
+
'.select { |dep| dep.groups.include?(:default) && dep.should_include? }' \
|
|
273
|
+
'.map(&:name)'
|
|
274
|
+
# @sg-ignore
|
|
275
|
+
# @type [Array<String>]
|
|
276
|
+
dep_names = query_external_bundle command
|
|
277
|
+
|
|
278
|
+
all_gemspecs_from_bundle.select { |gemspec| dep_names.include?(gemspec.name) }
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# @param gemspec [Gem::Specification]
|
|
283
|
+
# @return [Array<Gem::Dependency>]
|
|
284
|
+
def only_runtime_dependencies gemspec
|
|
285
|
+
unless gemspec.respond_to?(:dependencies) && gemspec.respond_to?(:development_dependencies)
|
|
286
|
+
gemspec = to_gem_specification(gemspec)
|
|
287
|
+
end
|
|
288
|
+
return [] if gemspec.nil?
|
|
289
|
+
|
|
290
|
+
gemspec.dependencies - gemspec.development_dependencies
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# @todo Should this be using Gem::SpecFetcher and pull them automatically?
|
|
294
|
+
#
|
|
295
|
+
# @param name [String]
|
|
296
|
+
# @param version_or_requirement [String, nil]
|
|
297
|
+
# @param out [IO, nil] output stream for logging
|
|
298
|
+
#
|
|
299
|
+
# @return [Gem::Specification, nil]
|
|
300
|
+
def resolve_gem_ignoring_local_bundle name, version_or_requirement = nil, out: $stderr
|
|
301
|
+
Gem::Specification.find_by_name(name, version_or_requirement)
|
|
302
|
+
rescue Gem::MissingSpecError
|
|
303
|
+
begin
|
|
304
|
+
Gem::Specification.find_by_name(name)
|
|
305
|
+
rescue Gem::MissingSpecError
|
|
306
|
+
stdlibmap = RbsMap::StdlibMap.new(name)
|
|
307
|
+
unless stdlibmap.resolved?
|
|
308
|
+
gem_desc = name
|
|
309
|
+
gem_desc += ":#{version_or_requirement}" if version_or_requirement
|
|
310
|
+
out&.puts "Please install the gem #{gem_desc} in Solargraph's Ruby environment"
|
|
311
|
+
end
|
|
312
|
+
nil # either not here or in stdlib
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# @sg-ignore flow sensitive typing needs better handling of ||= on lvars
|
|
317
|
+
# @return [Array<Gem::Specification>]
|
|
318
|
+
def all_gemspecs_from_external_bundle
|
|
319
|
+
@all_gemspecs_from_external_bundle ||=
|
|
320
|
+
begin
|
|
321
|
+
logger.info 'Fetching gemspecs required from external bundle'
|
|
322
|
+
|
|
323
|
+
command = 'specish_objects = Bundler.definition.locked_gems&.specs; ' \
|
|
324
|
+
'if specish_objects.first.respond_to?(:materialize_for_installation);' \
|
|
325
|
+
'specish_objects = specish_objects.map(&:materialize_for_installation);' \
|
|
326
|
+
'end;' \
|
|
327
|
+
'specish_objects.map { |specish| [specish.name, specish.version] }'
|
|
328
|
+
# @type [Array<Gem::Specification>]
|
|
329
|
+
query_external_bundle(command).map do |name, version|
|
|
330
|
+
resolve_gem_ignoring_local_bundle(name, version)
|
|
331
|
+
end.compact
|
|
332
|
+
rescue Solargraph::BundleNotFoundError => e
|
|
333
|
+
Solargraph.logger.info e.message
|
|
334
|
+
# @sg-ignore Need to add nil check here
|
|
335
|
+
Solargraph.logger.debug e.backtrace.join("\n")
|
|
336
|
+
[]
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# @return [Hash{String => Gem::Specification}]
|
|
341
|
+
def preference_map
|
|
342
|
+
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# @param gemspec [Gem::Specification]
|
|
346
|
+
#
|
|
347
|
+
# @return [Gem::Specification]
|
|
348
|
+
def gemspec_or_preference gemspec
|
|
349
|
+
return gemspec unless preference_map.key?(gemspec.name)
|
|
350
|
+
return gemspec if gemspec.version == preference_map[gemspec.name].version
|
|
351
|
+
|
|
352
|
+
change_gemspec_version gemspec, preference_map[gemspec.name].version
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# @param gemspec [Gem::Specification]
|
|
356
|
+
# @param version [String]
|
|
357
|
+
# @return [Gem::Specification]
|
|
358
|
+
def change_gemspec_version gemspec, version
|
|
359
|
+
Gem::Specification.find_by_name(gemspec.name, "= #{version}")
|
|
360
|
+
rescue Gem::MissingSpecError
|
|
361
|
+
Solargraph.logger.info "Gem #{gemspec.name} version #{version.inspect} not found. " \
|
|
362
|
+
"Using #{gemspec.version} instead"
|
|
363
|
+
gemspec
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
end
|
|
@@ -83,6 +83,7 @@ module Solargraph
|
|
|
83
83
|
return [] if hash.empty?
|
|
84
84
|
hash['paths'].map { |path| File.join(base, path) }
|
|
85
85
|
rescue StandardError => e
|
|
86
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
86
87
|
Solargraph.logger.warn "Error reading #{gemspec_file_path}: [#{e.class}] #{e.message}"
|
|
87
88
|
[]
|
|
88
89
|
end
|
data/lib/solargraph/workspace.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'open3'
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'yaml'
|
|
5
6
|
|
|
6
7
|
module Solargraph
|
|
7
8
|
# A workspace consists of the files in a project's directory and the
|
|
@@ -9,7 +10,10 @@ module Solargraph
|
|
|
9
10
|
# in an associated Library or ApiMap.
|
|
10
11
|
#
|
|
11
12
|
class Workspace
|
|
13
|
+
include Logging
|
|
14
|
+
|
|
12
15
|
autoload :Config, 'solargraph/workspace/config'
|
|
16
|
+
autoload :Gemspecs, 'solargraph/workspace/gemspecs'
|
|
13
17
|
autoload :RequirePaths, 'solargraph/workspace/require_paths'
|
|
14
18
|
|
|
15
19
|
# @return [String]
|
|
@@ -19,7 +23,8 @@ module Solargraph
|
|
|
19
23
|
attr_reader :gemnames
|
|
20
24
|
alias source_gems gemnames
|
|
21
25
|
|
|
22
|
-
# @
|
|
26
|
+
# @todo Remove '' and '*' special cases
|
|
27
|
+
# @param directory [String]
|
|
23
28
|
# @param config [Config, nil]
|
|
24
29
|
# @param server [Hash]
|
|
25
30
|
def initialize directory = '', config = nil, server = {}
|
|
@@ -50,6 +55,76 @@ module Solargraph
|
|
|
50
55
|
@config ||= Solargraph::Workspace::Config.new(directory)
|
|
51
56
|
end
|
|
52
57
|
|
|
58
|
+
# @param stdlib_name [String]
|
|
59
|
+
#
|
|
60
|
+
# @return [Array<String>]
|
|
61
|
+
def stdlib_dependencies stdlib_name
|
|
62
|
+
gemspecs.stdlib_dependencies(stdlib_name)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @param out [IO, nil] output stream for logging
|
|
66
|
+
# @param gemspec [Gem::Specification]
|
|
67
|
+
# @return [Array<Gem::Specification>]
|
|
68
|
+
def fetch_dependencies gemspec, out: $stderr
|
|
69
|
+
gemspecs.fetch_dependencies(gemspec, out: out)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @param require [String] The string sent to 'require' in the code to resolve, e.g. 'rails', 'bundler/require'
|
|
73
|
+
# @return [Array<Gem::Specification>, nil]
|
|
74
|
+
def resolve_require require
|
|
75
|
+
gemspecs.resolve_require(require)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @return [Solargraph::PinCache]
|
|
79
|
+
def pin_cache
|
|
80
|
+
@pin_cache ||= fresh_pincache
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @param stdlib_name [String]
|
|
84
|
+
#
|
|
85
|
+
# @return [Array<String>]
|
|
86
|
+
def stdlib_dependencies stdlib_name
|
|
87
|
+
deps = RbsMap::StdlibMap.stdlib_dependencies(stdlib_name, nil) || []
|
|
88
|
+
deps.map { |dep| dep['name'] }.compact
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @return [Environ]
|
|
92
|
+
def global_environ
|
|
93
|
+
# empty docmap, since the result needs to work in any possible
|
|
94
|
+
# context here
|
|
95
|
+
@global_environ ||= Convention.for_global(DocMap.new([], self, out: nil))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @param gemspec [Gem::Specification]
|
|
99
|
+
# @param out [StringIO, IO, nil] output stream for logging
|
|
100
|
+
# @param rebuild [Boolean] whether to rebuild the pins even if they are cached
|
|
101
|
+
#
|
|
102
|
+
# @return [void]
|
|
103
|
+
def cache_gem gemspec, out: nil, rebuild: false
|
|
104
|
+
pin_cache.cache_gem(gemspec: gemspec, out: out, rebuild: rebuild)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @param gemspec [Gem::Specification, Bundler::LazySpecification]
|
|
108
|
+
# @param out [StringIO, IO, nil] output stream for logging
|
|
109
|
+
#
|
|
110
|
+
# @return [void]
|
|
111
|
+
def uncache_gem gemspec, out: nil
|
|
112
|
+
pin_cache.uncache_gem(gemspec, out: out)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @return [Solargraph::PinCache]
|
|
116
|
+
def fresh_pincache
|
|
117
|
+
PinCache.new(rbs_collection_path: rbs_collection_path,
|
|
118
|
+
rbs_collection_config_path: rbs_collection_config_path,
|
|
119
|
+
yard_plugins: yard_plugins,
|
|
120
|
+
directory: directory)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @return [Array<String>]
|
|
124
|
+
def yard_plugins
|
|
125
|
+
@yard_plugins ||= global_environ.yard_plugins.sort.uniq
|
|
126
|
+
end
|
|
127
|
+
|
|
53
128
|
# @param level [Symbol]
|
|
54
129
|
# @return [TypeChecker::Rules]
|
|
55
130
|
def rules(level)
|
|
@@ -63,6 +138,7 @@ module Solargraph
|
|
|
63
138
|
# @param sources [Array<Solargraph::Source>]
|
|
64
139
|
# @return [Boolean] True if the source was added to the workspace
|
|
65
140
|
def merge *sources
|
|
141
|
+
# @sg-ignore Need to add nil check here
|
|
66
142
|
unless directory == '*' || sources.all? { |source| source_hash.key?(source.filename) }
|
|
67
143
|
# Reload the config to determine if a new source should be included
|
|
68
144
|
@config = Solargraph::Workspace::Config.new(directory)
|
|
@@ -70,10 +146,12 @@ module Solargraph
|
|
|
70
146
|
|
|
71
147
|
includes_any = false
|
|
72
148
|
sources.each do |source|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
149
|
+
# @sg-ignore Need to add nil check here
|
|
150
|
+
next unless directory == "*" || config.calculated.include?(source.filename)
|
|
151
|
+
|
|
152
|
+
# @sg-ignore Need to add nil check here
|
|
153
|
+
source_hash[source.filename] = source
|
|
154
|
+
includes_any = true
|
|
77
155
|
end
|
|
78
156
|
|
|
79
157
|
includes_any
|
|
@@ -126,6 +204,23 @@ module Solargraph
|
|
|
126
204
|
false
|
|
127
205
|
end
|
|
128
206
|
|
|
207
|
+
# True if the workspace contains at least one gemspec file.
|
|
208
|
+
#
|
|
209
|
+
# @return [Boolean]
|
|
210
|
+
def gemspec?
|
|
211
|
+
!gemspec_files.empty?
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Get an array of all gemspec files in the workspace.
|
|
215
|
+
#
|
|
216
|
+
# @return [Array<String>]
|
|
217
|
+
def gemspec_files
|
|
218
|
+
return [] if directory.empty? || directory == '*'
|
|
219
|
+
@gemspec_files ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
|
|
220
|
+
config.allow? gs
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
129
224
|
# @return [String, nil]
|
|
130
225
|
def rbs_collection_path
|
|
131
226
|
@gem_rbs_collection ||= read_rbs_collection_path
|
|
@@ -133,12 +228,57 @@ module Solargraph
|
|
|
133
228
|
|
|
134
229
|
# @return [String, nil]
|
|
135
230
|
def rbs_collection_config_path
|
|
136
|
-
@rbs_collection_config_path ||=
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
231
|
+
@rbs_collection_config_path ||=
|
|
232
|
+
begin
|
|
233
|
+
unless directory.empty? || directory == '*'
|
|
234
|
+
yaml_file = File.join(directory, 'rbs_collection.yaml')
|
|
235
|
+
yaml_file if File.file?(yaml_file)
|
|
236
|
+
end
|
|
140
237
|
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @param name [String]
|
|
241
|
+
# @param version [String, nil]
|
|
242
|
+
# @param out [IO, nil]
|
|
243
|
+
#
|
|
244
|
+
# @return [Gem::Specification, nil]
|
|
245
|
+
def find_gem name, version = nil, out: nil
|
|
246
|
+
gemspecs.find_gem(name, version, out: out)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# @return [Array<Gem::Specification>]
|
|
250
|
+
def all_gemspecs_from_bundle
|
|
251
|
+
gemspecs.all_gemspecs_from_bundle
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# @todo make this actually work against bundle instead of pulling
|
|
255
|
+
# all installed gemspecs -
|
|
256
|
+
# https://github.com/apiology/solargraph/pull/10
|
|
257
|
+
# @return [Array<Gem::Specification>]
|
|
258
|
+
def all_gemspecs_from_bundle
|
|
259
|
+
Gem::Specification.to_a
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# @param out [StringIO, IO, nil] output stream for logging
|
|
263
|
+
# @param rebuild [Boolean] whether to rebuild the pins even if they are cached
|
|
264
|
+
# @return [void]
|
|
265
|
+
def cache_all_for_workspace! out, rebuild: false
|
|
266
|
+
PinCache.cache_core(out: out) unless PinCache.core? && !rebuild
|
|
267
|
+
|
|
268
|
+
gem_specs = all_gemspecs_from_bundle
|
|
269
|
+
# try any possible standard libraries, but be quiet about it
|
|
270
|
+
stdlib_specs = pin_cache.possible_stdlibs.map { |stdlib| find_gem(stdlib, out: nil) }.compact
|
|
271
|
+
specs = (gem_specs + stdlib_specs)
|
|
272
|
+
specs.each do |spec|
|
|
273
|
+
pin_cache.cache_gem(gemspec: spec, rebuild: rebuild, out: out) unless pin_cache.cached?(spec)
|
|
141
274
|
end
|
|
275
|
+
out&.puts "Documentation cached for all #{specs.length} gems."
|
|
276
|
+
|
|
277
|
+
# do this after so that we prefer stdlib requires from gems,
|
|
278
|
+
# which are likely to be newer and have more pins
|
|
279
|
+
pin_cache.cache_all_stdlibs(out: out, rebuild: rebuild)
|
|
280
|
+
|
|
281
|
+
out&.puts "Documentation cached for core, standard library and gems."
|
|
142
282
|
end
|
|
143
283
|
|
|
144
284
|
# Synchronize the workspace from the provided updater.
|
|
@@ -149,7 +289,9 @@ module Solargraph
|
|
|
149
289
|
source_hash[updater.filename] = source_hash[updater.filename].synchronize(updater)
|
|
150
290
|
end
|
|
151
291
|
|
|
292
|
+
# @sg-ignore Need to validate config
|
|
152
293
|
# @return [String]
|
|
294
|
+
# @sg-ignore Need to validate config
|
|
153
295
|
def command_path
|
|
154
296
|
server['commandPath'] || 'solargraph'
|
|
155
297
|
end
|
|
@@ -160,12 +302,9 @@ module Solargraph
|
|
|
160
302
|
directory
|
|
161
303
|
end
|
|
162
304
|
|
|
163
|
-
#
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
#
|
|
167
|
-
def gemfile?
|
|
168
|
-
directory && File.file?(File.join(directory, 'Gemfile'))
|
|
305
|
+
# @return [Solargraph::Workspace::Gemspecs]
|
|
306
|
+
def gemspecs
|
|
307
|
+
@gemspecs ||= Solargraph::Workspace::Gemspecs.new(directory_or_nil)
|
|
169
308
|
end
|
|
170
309
|
|
|
171
310
|
private
|
|
@@ -186,7 +325,10 @@ module Solargraph
|
|
|
186
325
|
source_hash.clear
|
|
187
326
|
unless directory.empty? || directory == '*'
|
|
188
327
|
size = config.calculated.length
|
|
189
|
-
|
|
328
|
+
if config.max_files > 0 and size > config.max_files
|
|
329
|
+
raise WorkspaceTooLargeError,
|
|
330
|
+
"The workspace is too large to index (#{size} files, #{config.max_files} max)"
|
|
331
|
+
end
|
|
190
332
|
config.calculated.each do |filename|
|
|
191
333
|
begin
|
|
192
334
|
source_hash[filename] = Solargraph::Source.load(filename)
|
|
@@ -5,7 +5,7 @@ module Solargraph
|
|
|
5
5
|
|
|
6
6
|
# @param code_object [YARD::CodeObjects::Base]
|
|
7
7
|
# @param spec [Gem::Specification, nil]
|
|
8
|
-
# @return [Solargraph::Location
|
|
8
|
+
# @return [Solargraph::Location]
|
|
9
9
|
def object_location code_object, spec
|
|
10
10
|
if spec.nil? || code_object.nil? || code_object.file.nil? || code_object.line.nil?
|
|
11
11
|
if code_object.namespace.is_a?(YARD::CodeObjects::NamespaceObject)
|
|
@@ -14,6 +14,7 @@ module Solargraph
|
|
|
14
14
|
end
|
|
15
15
|
return Solargraph::Location.new(__FILE__, Solargraph::Range.from_to(__LINE__ - 1, 0, __LINE__ - 1, 0))
|
|
16
16
|
end
|
|
17
|
+
# @sg-ignore flow sensitive typing should be able to identify more blocks that always return
|
|
17
18
|
file = File.join(spec.full_gem_path, code_object.file)
|
|
18
19
|
Solargraph::Location.new(file, Solargraph::Range.from_to(code_object.line - 1, 0, code_object.line - 1, 0))
|
|
19
20
|
end
|
|
@@ -6,6 +6,7 @@ module Solargraph
|
|
|
6
6
|
module ToMethod
|
|
7
7
|
extend YardMap::Helpers
|
|
8
8
|
|
|
9
|
+
# @type [Hash{Array<String, Symbol, String> => Symbol}]
|
|
9
10
|
VISIBILITY_OVERRIDE = {
|
|
10
11
|
# YARD pays attention to 'private' statements prior to class methods but shouldn't
|
|
11
12
|
["Rails::Engine", :class, "find_root_with_flag"] => :public
|
|
@@ -25,9 +26,12 @@ module Solargraph
|
|
|
25
26
|
return_type = ComplexType::SELF if name == 'new'
|
|
26
27
|
comments = code_object.docstring ? code_object.docstring.all.to_s : ''
|
|
27
28
|
final_scope = scope || code_object.scope
|
|
29
|
+
# @sg-ignore Need to add nil check here
|
|
28
30
|
override_key = [closure.path, final_scope, name]
|
|
29
31
|
final_visibility = VISIBILITY_OVERRIDE[override_key]
|
|
32
|
+
# @sg-ignore Need to add nil check here
|
|
30
33
|
final_visibility ||= VISIBILITY_OVERRIDE[[closure.path, final_scope]]
|
|
34
|
+
# @sg-ignore Need to add nil check here
|
|
31
35
|
final_visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(name.to_sym)
|
|
32
36
|
final_visibility ||= visibility
|
|
33
37
|
final_visibility ||= :private if code_object.module_function? && final_scope == :instance
|
|
@@ -49,6 +53,7 @@ module Solargraph
|
|
|
49
53
|
source: :yardoc,
|
|
50
54
|
)
|
|
51
55
|
else
|
|
56
|
+
# @sg-ignore Need to add nil check here
|
|
52
57
|
pin = Pin::Method.new(
|
|
53
58
|
location: location,
|
|
54
59
|
closure: closure,
|
|
@@ -85,7 +90,6 @@ module Solargraph
|
|
|
85
90
|
# HACK: Skip `nil` and `self` parameters that are sometimes emitted
|
|
86
91
|
# for methods defined in C
|
|
87
92
|
# See https://github.com/castwide/solargraph/issues/345
|
|
88
|
-
# @sg-ignore https://github.com/castwide/solargraph/pull/1114
|
|
89
93
|
code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
|
|
90
94
|
Solargraph::Pin::Parameter.new(
|
|
91
95
|
location: location,
|