solargraph 0.56.0 → 0.58.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/.gitattributes +2 -0
- data/.github/workflows/linting.yml +127 -0
- data/.github/workflows/plugins.yml +183 -7
- data/.github/workflows/rspec.yml +55 -5
- data/.github/workflows/typecheck.yml +6 -3
- data/.gitignore +5 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +1279 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +86 -1
- data/README.md +8 -4
- data/Rakefile +125 -13
- data/bin/solargraph +3 -0
- data/lib/solargraph/api_map/cache.rb +3 -2
- data/lib/solargraph/api_map/constants.rb +279 -0
- data/lib/solargraph/api_map/index.rb +49 -31
- data/lib/solargraph/api_map/source_to_yard.rb +13 -4
- data/lib/solargraph/api_map/store.rb +144 -26
- data/lib/solargraph/api_map.rb +217 -245
- data/lib/solargraph/bench.rb +1 -0
- data/lib/solargraph/complex_type/type_methods.rb +6 -0
- data/lib/solargraph/complex_type/unique_type.rb +19 -12
- data/lib/solargraph/complex_type.rb +24 -3
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +17 -0
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
- data/lib/solargraph/convention/data_definition.rb +105 -0
- data/lib/solargraph/convention/gemspec.rb +3 -2
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -2
- data/lib/solargraph/convention/struct_definition.rb +87 -24
- data/lib/solargraph/convention.rb +32 -2
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
- data/lib/solargraph/doc_map.rb +52 -18
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/equality.rb +1 -0
- data/lib/solargraph/gem_pins.rb +21 -11
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +3 -0
- data/lib/solargraph/language_server/host.rb +12 -5
- data/lib/solargraph/language_server/message/base.rb +2 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +19 -2
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
- data/lib/solargraph/language_server/progress.rb +8 -0
- data/lib/solargraph/language_server/request.rb +4 -1
- data/lib/solargraph/library.rb +50 -33
- data/lib/solargraph/location.rb +3 -0
- data/lib/solargraph/logging.rb +11 -2
- data/lib/solargraph/page.rb +3 -0
- data/lib/solargraph/parser/comment_ripper.rb +8 -1
- data/lib/solargraph/parser/flow_sensitive_typing.rb +33 -5
- data/lib/solargraph/parser/node_processor/base.rb +10 -5
- data/lib/solargraph/parser/node_processor.rb +24 -8
- data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -13
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -16
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +1 -21
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +0 -22
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +65 -8
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +12 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +36 -16
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
- data/lib/solargraph/parser/region.rb +3 -0
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/pin/base.rb +92 -14
- data/lib/solargraph/pin/base_variable.rb +6 -5
- data/lib/solargraph/pin/block.rb +3 -2
- data/lib/solargraph/pin/callable.rb +14 -1
- data/lib/solargraph/pin/closure.rb +5 -7
- data/lib/solargraph/pin/common.rb +6 -2
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/local_variable.rb +1 -2
- data/lib/solargraph/pin/method.rb +32 -11
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/parameter.rb +24 -10
- data/lib/solargraph/pin/proxy_type.rb +5 -1
- data/lib/solargraph/pin/reference/override.rb +15 -1
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +17 -0
- data/lib/solargraph/pin/search.rb +6 -1
- data/lib/solargraph/pin/signature.rb +2 -0
- data/lib/solargraph/pin/symbol.rb +5 -0
- data/lib/solargraph/pin_cache.rb +64 -4
- data/lib/solargraph/position.rb +3 -0
- data/lib/solargraph/range.rb +5 -0
- data/lib/solargraph/rbs_map/conversions.rb +68 -18
- data/lib/solargraph/rbs_map/core_fills.rb +18 -0
- data/lib/solargraph/rbs_map/core_map.rb +14 -7
- data/lib/solargraph/rbs_map.rb +14 -1
- data/lib/solargraph/shell.rb +85 -1
- data/lib/solargraph/source/chain/call.rb +7 -3
- data/lib/solargraph/source/chain/constant.rb +3 -66
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +11 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +11 -2
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +2 -3
- data/lib/solargraph/source/encoding_fixes.rb +23 -23
- data/lib/solargraph/source/source_chainer.rb +1 -1
- data/lib/solargraph/source.rb +6 -3
- data/lib/solargraph/source_map/clip.rb +18 -26
- data/lib/solargraph/source_map/data.rb +4 -0
- data/lib/solargraph/source_map/mapper.rb +2 -2
- data/lib/solargraph/source_map.rb +28 -16
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +30 -8
- data/lib/solargraph/type_checker.rb +301 -186
- data/lib/solargraph/version.rb +5 -5
- data/lib/solargraph/workspace/config.rb +22 -6
- data/lib/solargraph/workspace/require_paths.rb +97 -0
- data/lib/solargraph/workspace.rb +38 -67
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +5 -9
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +8 -7
- data/lib/solargraph/yard_map/to_method.rb +2 -1
- data/lib/solargraph/yardoc.rb +41 -3
- data/lib/solargraph.rb +15 -0
- data/rbs/fills/bundler/0/bundler.rbs +4271 -0
- data/rbs/fills/open3/0/open3.rbs +172 -0
- data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
- data/rbs/fills/rubygems/0/errors.rbs +364 -0
- data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
- data/rbs/fills/rubygems/0/specification.rbs +1753 -0
- data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +2 -3
- data/rbs_collection.yaml +4 -4
- data/sig/shims/ast/0/node.rbs +5 -0
- data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
- data/sig/shims/ast/2.4/ast.rbs +73 -0
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
- data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
- data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
- data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
- data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
- data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
- data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
- data/solargraph.gemspec +26 -5
- metadata +187 -15
- data/lib/.rubocop.yml +0 -22
- data/lib/solargraph/parser/node_methods.rb +0 -97
|
@@ -8,8 +8,9 @@ module Solargraph
|
|
|
8
8
|
|
|
9
9
|
module NodeProcessors
|
|
10
10
|
class StructNode < Parser::NodeProcessor::Base
|
|
11
|
+
# @return [Boolean] continue processing the next processor of the same node.
|
|
11
12
|
def process
|
|
12
|
-
return if struct_definition_node.nil?
|
|
13
|
+
return true if struct_definition_node.nil?
|
|
13
14
|
|
|
14
15
|
loc = get_node_location(node)
|
|
15
16
|
nspin = Solargraph::Pin::Namespace.new(
|
|
@@ -17,9 +18,10 @@ module Solargraph
|
|
|
17
18
|
location: loc,
|
|
18
19
|
closure: region.closure,
|
|
19
20
|
name: struct_definition_node.class_name,
|
|
20
|
-
|
|
21
|
+
docstring: docstring,
|
|
21
22
|
visibility: :public,
|
|
22
|
-
gates: region.closure.gates.freeze
|
|
23
|
+
gates: region.closure.gates.freeze,
|
|
24
|
+
source: :struct_definition
|
|
23
25
|
)
|
|
24
26
|
pins.push nspin
|
|
25
27
|
|
|
@@ -31,7 +33,8 @@ module Solargraph
|
|
|
31
33
|
location: get_node_location(node),
|
|
32
34
|
closure: nspin,
|
|
33
35
|
visibility: :private,
|
|
34
|
-
|
|
36
|
+
docstring: docstring,
|
|
37
|
+
source: :struct_definition
|
|
35
38
|
)
|
|
36
39
|
|
|
37
40
|
pins.push initialize_method_pin
|
|
@@ -42,7 +45,8 @@ module Solargraph
|
|
|
42
45
|
name: attribute_name,
|
|
43
46
|
decl: struct_definition_node.keyword_init? ? :kwarg : :arg,
|
|
44
47
|
location: get_node_location(attribute_node),
|
|
45
|
-
closure: initialize_method_pin
|
|
48
|
+
closure: initialize_method_pin,
|
|
49
|
+
source: :struct_definition
|
|
46
50
|
)
|
|
47
51
|
)
|
|
48
52
|
end
|
|
@@ -50,49 +54,108 @@ module Solargraph
|
|
|
50
54
|
# define attribute accessors and instance variables
|
|
51
55
|
struct_definition_node.attributes.each do |attribute_node, attribute_name|
|
|
52
56
|
[attribute_name, "#{attribute_name}="].each do |name|
|
|
57
|
+
docs = docstring.tags.find { |t| t.tag_name == 'param' && t.name == attribute_name }
|
|
58
|
+
|
|
59
|
+
attribute_type = ComplexType.parse(tag_string(docs))
|
|
60
|
+
return_type_comment = attribute_comment(docs, false)
|
|
61
|
+
param_comment = attribute_comment(docs, true)
|
|
62
|
+
|
|
53
63
|
method_pin = Pin::Method.new(
|
|
54
64
|
name: name,
|
|
55
65
|
parameters: [],
|
|
56
66
|
scope: :instance,
|
|
57
67
|
location: get_node_location(attribute_node),
|
|
58
68
|
closure: nspin,
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
docstring: YARD::Docstring.new(return_type_comment),
|
|
70
|
+
# even assignments return the value
|
|
71
|
+
comments: return_type_comment,
|
|
72
|
+
return_type: attribute_type,
|
|
73
|
+
visibility: :public,
|
|
74
|
+
source: :struct_definition
|
|
61
75
|
)
|
|
62
76
|
|
|
63
|
-
|
|
77
|
+
if name.end_with?('=')
|
|
78
|
+
method_pin.parameters << Pin::Parameter.new(
|
|
79
|
+
name: attribute_name,
|
|
80
|
+
location: get_node_location(attribute_node),
|
|
81
|
+
closure: method_pin,
|
|
82
|
+
return_type: attribute_type,
|
|
83
|
+
comments: param_comment,
|
|
84
|
+
source: :struct_definition
|
|
85
|
+
)
|
|
64
86
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
87
|
+
pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
|
|
88
|
+
closure: method_pin,
|
|
89
|
+
location: get_node_location(attribute_node),
|
|
90
|
+
return_type: attribute_type,
|
|
91
|
+
comments: "@type [#{attribute_type.rooted_tags}]",
|
|
92
|
+
source: :struct_definition)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
pins.push method_pin
|
|
70
96
|
end
|
|
71
97
|
end
|
|
72
98
|
|
|
73
99
|
process_children region.update(closure: nspin, visibility: :public)
|
|
100
|
+
false
|
|
74
101
|
end
|
|
75
102
|
|
|
76
103
|
private
|
|
77
104
|
|
|
78
|
-
# @return [StructDefintionNode, nil]
|
|
105
|
+
# @return [StructDefintionNode, StructAssignmentNode, nil]
|
|
79
106
|
def struct_definition_node
|
|
80
|
-
@struct_definition_node ||= if StructDefintionNode.
|
|
107
|
+
@struct_definition_node ||= if StructDefintionNode.match?(node)
|
|
81
108
|
StructDefintionNode.new(node)
|
|
82
|
-
elsif StructAssignmentNode.
|
|
109
|
+
elsif StructAssignmentNode.match?(node)
|
|
83
110
|
StructAssignmentNode.new(node)
|
|
84
111
|
end
|
|
85
112
|
end
|
|
86
113
|
|
|
87
|
-
#
|
|
88
|
-
# @return [
|
|
89
|
-
def
|
|
90
|
-
|
|
91
|
-
|
|
114
|
+
# Gets/generates the relevant docstring for this struct & it's attributes
|
|
115
|
+
# @return [YARD::Docstring]
|
|
116
|
+
def docstring
|
|
117
|
+
@docstring ||= parse_comments
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Parses any relevant comments for a struct int a yard docstring
|
|
121
|
+
# @return [YARD::Docstring]
|
|
122
|
+
def parse_comments
|
|
123
|
+
struct_comments = comments_for(node) || ''
|
|
124
|
+
struct_definition_node.attributes.each do |attr_node, attr_name|
|
|
125
|
+
comment = comments_for(attr_node)
|
|
126
|
+
next if comment.nil?
|
|
92
127
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
128
|
+
# We should support specific comments for an attribute, and that can be either a @return on an @param
|
|
129
|
+
# But since we merge into the struct_comments, then we should interpret either as a param
|
|
130
|
+
comment = "@param #{attr_name}#{comment[7..]}" if comment.start_with?('@return')
|
|
131
|
+
|
|
132
|
+
struct_comments += "\n#{comment}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
Solargraph::Source.parse_docstring(struct_comments).to_docstring
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @param tag [YARD::Tags::Tag, nil] The param tag for this attribute.xtract_
|
|
139
|
+
#
|
|
140
|
+
# @return [String]
|
|
141
|
+
def tag_string(tag)
|
|
142
|
+
tag&.types&.join(',') || 'undefined'
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @param tag [YARD::Tags::Tag, nil] The param tag for this attribute. If nil, this method is a no-op
|
|
146
|
+
# @param for_setter [Boolean] If true, will return a @param tag instead of a @return tag
|
|
147
|
+
#
|
|
148
|
+
# @return [String] The formatted comment for the attribute
|
|
149
|
+
def attribute_comment(tag, for_setter)
|
|
150
|
+
return "" if tag.nil?
|
|
151
|
+
|
|
152
|
+
suffix = "[#{tag_string(tag)}] #{tag.text}"
|
|
153
|
+
|
|
154
|
+
if for_setter
|
|
155
|
+
"@param #{tag.name} #{suffix}"
|
|
156
|
+
else
|
|
157
|
+
"@return #{suffix}"
|
|
158
|
+
end
|
|
96
159
|
end
|
|
97
160
|
end
|
|
98
161
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
module Solargraph
|
|
5
4
|
# Conventions provide a way to modify an ApiMap based on expectations about
|
|
6
5
|
# one of its sources.
|
|
@@ -11,6 +10,8 @@ module Solargraph
|
|
|
11
10
|
autoload :Gemspec, 'solargraph/convention/gemspec'
|
|
12
11
|
autoload :Rakefile, 'solargraph/convention/rakefile'
|
|
13
12
|
autoload :StructDefinition, 'solargraph/convention/struct_definition'
|
|
13
|
+
autoload :DataDefinition, 'solargraph/convention/data_definition'
|
|
14
|
+
autoload :ActiveSupportConcern, 'solargraph/convention/active_support_concern'
|
|
14
15
|
|
|
15
16
|
# @type [Set<Convention::Base>]
|
|
16
17
|
@@conventions = Set.new
|
|
@@ -21,6 +22,12 @@ module Solargraph
|
|
|
21
22
|
@@conventions.add convention.new
|
|
22
23
|
end
|
|
23
24
|
|
|
25
|
+
# @param convention [Class<Convention::Base>]
|
|
26
|
+
# @return [void]
|
|
27
|
+
def self.unregister convention
|
|
28
|
+
@@conventions.delete_if { |c| c.is_a?(convention) }
|
|
29
|
+
end
|
|
30
|
+
|
|
24
31
|
# @param source_map [SourceMap]
|
|
25
32
|
# @return [Environ]
|
|
26
33
|
def self.for_local(source_map)
|
|
@@ -31,7 +38,7 @@ module Solargraph
|
|
|
31
38
|
result
|
|
32
39
|
end
|
|
33
40
|
|
|
34
|
-
# @param
|
|
41
|
+
# @param doc_map [DocMap]
|
|
35
42
|
# @return [Environ]
|
|
36
43
|
def self.for_global(doc_map)
|
|
37
44
|
result = Environ.new
|
|
@@ -41,8 +48,31 @@ module Solargraph
|
|
|
41
48
|
result
|
|
42
49
|
end
|
|
43
50
|
|
|
51
|
+
# Provides any additional method pins based on the described object.
|
|
52
|
+
#
|
|
53
|
+
# @param api_map [ApiMap]
|
|
54
|
+
# @param rooted_tag [String] A fully qualified namespace, with
|
|
55
|
+
# generic parameter values if applicable
|
|
56
|
+
# @param scope [Symbol] :class or :instance
|
|
57
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
|
58
|
+
# @param deep [Boolean]
|
|
59
|
+
# @param skip [Set<String>]
|
|
60
|
+
# @param no_core [Boolean] Skip core classes if true
|
|
61
|
+
#
|
|
62
|
+
# @return [Environ]
|
|
63
|
+
def self.for_object api_map, rooted_tag, scope, visibility,
|
|
64
|
+
deep, skip, no_core
|
|
65
|
+
result = Environ.new
|
|
66
|
+
@@conventions.each do |conv|
|
|
67
|
+
result.merge conv.object(api_map, rooted_tag, scope, visibility,
|
|
68
|
+
deep, skip, no_core)
|
|
69
|
+
end
|
|
70
|
+
result
|
|
71
|
+
end
|
|
72
|
+
|
|
44
73
|
register Gemfile
|
|
45
74
|
register Gemspec
|
|
46
75
|
register Rakefile
|
|
76
|
+
register ActiveSupportConcern
|
|
47
77
|
end
|
|
48
78
|
end
|
|
@@ -28,7 +28,12 @@ module Solargraph
|
|
|
28
28
|
options, paths = generate_options(source.filename, source.code)
|
|
29
29
|
store = RuboCop::ConfigStore.new
|
|
30
30
|
runner = RuboCop::Runner.new(options, store)
|
|
31
|
-
|
|
31
|
+
# Ensure only one instance of RuboCop::Runner is running at
|
|
32
|
+
# a time - it uses 'chdir' to read config files with ERB,
|
|
33
|
+
# which can conflict with other chdirs.
|
|
34
|
+
result = Solargraph::CHDIR_MUTEX.synchronize do
|
|
35
|
+
redirect_stdout{ runner.run(paths) }
|
|
36
|
+
end
|
|
32
37
|
|
|
33
38
|
return [] if result.empty?
|
|
34
39
|
|
|
@@ -15,15 +15,16 @@ module Solargraph
|
|
|
15
15
|
# @return [void]
|
|
16
16
|
def require_rubocop(version = nil)
|
|
17
17
|
begin
|
|
18
|
+
# @type [String]
|
|
18
19
|
gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
|
|
19
20
|
gem_lib_path = File.join(gem_path, 'lib')
|
|
20
21
|
$LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
|
|
21
|
-
# @todo Gem::MissingSpecVersionError is undocumented for some reason
|
|
22
|
-
# @sg-ignore
|
|
23
22
|
rescue Gem::MissingSpecVersionError => e
|
|
23
|
+
# @type [Array<Gem::Specification>]
|
|
24
|
+
specs = e.specs
|
|
24
25
|
raise InvalidRubocopVersionError,
|
|
25
26
|
"could not find '#{e.name}' (#{e.requirement}) - "\
|
|
26
|
-
"did find: [#{
|
|
27
|
+
"did find: [#{specs.map { |s| s.version.version }.join(', ')}]"
|
|
27
28
|
end
|
|
28
29
|
require 'rubocop'
|
|
29
30
|
end
|
|
@@ -37,6 +38,7 @@ module Solargraph
|
|
|
37
38
|
args = ['-f', 'j', '--force-exclusion', filename]
|
|
38
39
|
base_options = RuboCop::Options.new
|
|
39
40
|
options, paths = base_options.parse(args)
|
|
41
|
+
# @sg-ignore
|
|
40
42
|
options[:stdin] = code
|
|
41
43
|
[options, paths]
|
|
42
44
|
end
|
data/lib/solargraph/doc_map.rb
CHANGED
|
@@ -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.
|
|
@@ -21,8 +22,9 @@ module Solargraph
|
|
|
21
22
|
|
|
22
23
|
# @return [Array<Gem::Specification>]
|
|
23
24
|
def uncached_gemspecs
|
|
24
|
-
(
|
|
25
|
-
|
|
25
|
+
uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs)
|
|
26
|
+
.sort
|
|
27
|
+
.uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
# @return [Array<Gem::Specification>]
|
|
@@ -31,8 +33,10 @@ module Solargraph
|
|
|
31
33
|
# @return [Array<Gem::Specification>]
|
|
32
34
|
attr_reader :uncached_rbs_collection_gemspecs
|
|
33
35
|
|
|
36
|
+
# @return [String, nil]
|
|
34
37
|
attr_reader :rbs_collection_path
|
|
35
38
|
|
|
39
|
+
# @return [String, nil]
|
|
36
40
|
attr_reader :rbs_collection_config_path
|
|
37
41
|
|
|
38
42
|
# @return [Workspace, nil]
|
|
@@ -51,10 +55,13 @@ module Solargraph
|
|
|
51
55
|
@rbs_collection_path = workspace&.rbs_collection_path
|
|
52
56
|
@rbs_collection_config_path = workspace&.rbs_collection_config_path
|
|
53
57
|
@environ = Convention.for_global(self)
|
|
58
|
+
@requires.concat @environ.requires if @environ
|
|
54
59
|
load_serialized_gem_pins
|
|
55
60
|
pins.concat @environ.pins
|
|
56
61
|
end
|
|
57
62
|
|
|
63
|
+
# @param out [IO]
|
|
64
|
+
# @return [void]
|
|
58
65
|
def cache_all!(out)
|
|
59
66
|
# if we log at debug level:
|
|
60
67
|
if logger.info?
|
|
@@ -72,12 +79,18 @@ module Solargraph
|
|
|
72
79
|
@uncached_yard_gemspecs = []
|
|
73
80
|
end
|
|
74
81
|
|
|
82
|
+
# @param gemspec [Gem::Specification]
|
|
83
|
+
# @param out [IO]
|
|
84
|
+
# @return [void]
|
|
75
85
|
def cache_yard_pins(gemspec, out)
|
|
76
|
-
pins = GemPins.build_yard_pins(gemspec)
|
|
86
|
+
pins = GemPins.build_yard_pins(yard_plugins, gemspec)
|
|
77
87
|
PinCache.serialize_yard_gem(gemspec, pins)
|
|
78
88
|
logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
|
|
79
89
|
end
|
|
80
90
|
|
|
91
|
+
# @param gemspec [Gem::Specification]
|
|
92
|
+
# @param out [IO]
|
|
93
|
+
# @return [void]
|
|
81
94
|
def cache_rbs_collection_pins(gemspec, out)
|
|
82
95
|
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
|
83
96
|
pins = rbs_map.pins
|
|
@@ -89,6 +102,9 @@ module Solargraph
|
|
|
89
102
|
end
|
|
90
103
|
|
|
91
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]
|
|
92
108
|
def cache(gemspec, rebuild: false, out: nil)
|
|
93
109
|
build_yard = uncached_yard_gemspecs.include?(gemspec) || rebuild
|
|
94
110
|
build_rbs_collection = uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
|
|
@@ -112,30 +128,42 @@ module Solargraph
|
|
|
112
128
|
@unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
|
|
113
129
|
end
|
|
114
130
|
|
|
131
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
115
132
|
def self.all_yard_gems_in_memory
|
|
116
133
|
@yard_gems_in_memory ||= {}
|
|
117
134
|
end
|
|
118
135
|
|
|
136
|
+
# @return [Hash{String => Hash{Array(String, String) => Array<Pin::Base>}}] stored by RBS collection path
|
|
119
137
|
def self.all_rbs_collection_gems_in_memory
|
|
120
138
|
@rbs_collection_gems_in_memory ||= {}
|
|
121
139
|
end
|
|
122
140
|
|
|
141
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
123
142
|
def yard_pins_in_memory
|
|
124
143
|
self.class.all_yard_gems_in_memory
|
|
125
144
|
end
|
|
126
145
|
|
|
146
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
127
147
|
def rbs_collection_pins_in_memory
|
|
128
148
|
self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
|
|
129
149
|
end
|
|
130
150
|
|
|
151
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
131
152
|
def self.all_combined_pins_in_memory
|
|
132
153
|
@combined_pins_in_memory ||= {}
|
|
133
154
|
end
|
|
134
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
|
|
135
158
|
def combined_pins_in_memory
|
|
136
159
|
self.class.all_combined_pins_in_memory
|
|
137
160
|
end
|
|
138
161
|
|
|
162
|
+
# @return [Array<String>]
|
|
163
|
+
def yard_plugins
|
|
164
|
+
@environ.yard_plugins
|
|
165
|
+
end
|
|
166
|
+
|
|
139
167
|
# @return [Set<Gem::Specification>]
|
|
140
168
|
def dependencies
|
|
141
169
|
@dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
|
|
@@ -149,7 +177,11 @@ module Solargraph
|
|
|
149
177
|
@uncached_yard_gemspecs = []
|
|
150
178
|
@uncached_rbs_collection_gemspecs = []
|
|
151
179
|
with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
|
|
180
|
+
# @sg-ignore Need support for RBS duck interfaces like _ToHash
|
|
181
|
+
# @type [Array<String>]
|
|
152
182
|
paths = Hash[without_gemspecs].keys
|
|
183
|
+
# @sg-ignore Need support for RBS duck interfaces like _ToHash
|
|
184
|
+
# @type [Array<Gem::Specification>]
|
|
153
185
|
gemspecs = Hash[with_gemspecs].values.flatten.compact + dependencies.to_a
|
|
154
186
|
|
|
155
187
|
paths.each do |path|
|
|
@@ -180,7 +212,7 @@ module Solargraph
|
|
|
180
212
|
end
|
|
181
213
|
|
|
182
214
|
# @param gemspec [Gem::Specification]
|
|
183
|
-
# @return [Array<Pin::Base
|
|
215
|
+
# @return [Array<Pin::Base>, nil]
|
|
184
216
|
def deserialize_yard_pin_cache gemspec
|
|
185
217
|
if yard_pins_in_memory.key?([gemspec.name, gemspec.version])
|
|
186
218
|
return yard_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
@@ -258,6 +290,8 @@ module Solargraph
|
|
|
258
290
|
end
|
|
259
291
|
end
|
|
260
292
|
|
|
293
|
+
# @param gemspec [Gem::Specification]
|
|
294
|
+
# @param rbs_version_cache_key [String]
|
|
261
295
|
# @return [Array<Pin::Base>, nil]
|
|
262
296
|
def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
|
263
297
|
return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
|
|
@@ -273,22 +307,13 @@ module Solargraph
|
|
|
273
307
|
end
|
|
274
308
|
end
|
|
275
309
|
|
|
276
|
-
# @param gemspec [Gem::Specification]
|
|
277
|
-
# @return [Boolean]
|
|
278
|
-
def try_gem_in_memory gemspec
|
|
279
|
-
gempins = DocMap.gems_in_memory[gemspec]
|
|
280
|
-
return false unless gempins
|
|
281
|
-
Solargraph.logger.debug "Found #{gemspec.name} #{gemspec.version} in memory"
|
|
282
|
-
@pins.concat gempins
|
|
283
|
-
true
|
|
284
|
-
end
|
|
285
|
-
|
|
286
310
|
# @param path [String]
|
|
287
311
|
# @return [::Array<Gem::Specification>, nil]
|
|
288
312
|
def resolve_path_to_gemspecs path
|
|
289
313
|
return nil if path.empty?
|
|
290
314
|
return gemspecs_required_from_bundler if path == 'bundler/require'
|
|
291
315
|
|
|
316
|
+
# @type [Gem::Specification, nil]
|
|
292
317
|
gemspec = Gem::Specification.find_by_path(path)
|
|
293
318
|
if gemspec.nil?
|
|
294
319
|
gem_name_guess = path.split('/').first
|
|
@@ -312,10 +337,12 @@ module Solargraph
|
|
|
312
337
|
# @param gemspec [Gem::Specification]
|
|
313
338
|
# @return [Gem::Specification]
|
|
314
339
|
def gemspec_or_preference gemspec
|
|
340
|
+
# :nocov: dormant feature
|
|
315
341
|
return gemspec unless preference_map.key?(gemspec.name)
|
|
316
342
|
return gemspec if gemspec.version == preference_map[gemspec.name].version
|
|
317
343
|
|
|
318
|
-
change_gemspec_version gemspec, preference_map[
|
|
344
|
+
change_gemspec_version gemspec, preference_map[gemspec.name].version
|
|
345
|
+
# :nocov:
|
|
319
346
|
end
|
|
320
347
|
|
|
321
348
|
# @param gemspec [Gem::Specification]
|
|
@@ -332,13 +359,16 @@ module Solargraph
|
|
|
332
359
|
# @return [Array<Gem::Specification>]
|
|
333
360
|
def fetch_dependencies gemspec
|
|
334
361
|
# @param spec [Gem::Dependency]
|
|
362
|
+
# @param deps [Set<Gem::Specification>]
|
|
335
363
|
only_runtime_dependencies(gemspec).each_with_object(Set.new) do |spec, deps|
|
|
336
364
|
Solargraph.logger.info "Adding #{spec.name} dependency for #{gemspec.name}"
|
|
337
365
|
dep = Gem.loaded_specs[spec.name]
|
|
338
366
|
# @todo is next line necessary?
|
|
367
|
+
# @sg-ignore Unresolved call to requirement on Gem::Dependency
|
|
339
368
|
dep ||= Gem::Specification.find_by_name(spec.name, spec.requirement)
|
|
340
369
|
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
|
341
370
|
rescue Gem::MissingSpecError
|
|
371
|
+
# @sg-ignore Unresolved call to requirement on Gem::Dependency
|
|
342
372
|
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found in RubyGems."
|
|
343
373
|
end.to_a
|
|
344
374
|
end
|
|
@@ -354,8 +384,12 @@ module Solargraph
|
|
|
354
384
|
self.class.inspect
|
|
355
385
|
end
|
|
356
386
|
|
|
387
|
+
# @return [Array<Gem::Specification>, nil]
|
|
357
388
|
def gemspecs_required_from_bundler
|
|
358
|
-
|
|
389
|
+
# @todo Handle projects with custom Bundler/Gemfile setups
|
|
390
|
+
return unless workspace.gemfile?
|
|
391
|
+
|
|
392
|
+
if workspace.gemfile? && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory)
|
|
359
393
|
# Find only the gems bundler is now using
|
|
360
394
|
Bundler.definition.locked_gems.specs.flat_map do |lazy_spec|
|
|
361
395
|
logger.info "Handling #{lazy_spec.name}:#{lazy_spec.version}"
|
|
@@ -373,6 +407,7 @@ module Solargraph
|
|
|
373
407
|
end
|
|
374
408
|
end
|
|
375
409
|
|
|
410
|
+
# @return [Array<Gem::Specification>, nil]
|
|
376
411
|
def gemspecs_required_from_external_bundle
|
|
377
412
|
logger.info 'Fetching gemspecs required from external bundle'
|
|
378
413
|
return [] unless workspace&.directory
|
|
@@ -396,8 +431,7 @@ module Solargraph
|
|
|
396
431
|
next specs
|
|
397
432
|
end.compact
|
|
398
433
|
else
|
|
399
|
-
Solargraph.logger.warn e
|
|
400
|
-
raise BundleNotFoundError, "Failed to load gems from bundle at #{workspace&.directory}"
|
|
434
|
+
Solargraph.logger.warn "Failed to load gems from bundle at #{workspace&.directory}: #{e}"
|
|
401
435
|
end
|
|
402
436
|
end
|
|
403
437
|
end
|
data/lib/solargraph/environ.rb
CHANGED
|
@@ -13,16 +13,21 @@ module Solargraph
|
|
|
13
13
|
# @return [Array<String>]
|
|
14
14
|
attr_reader :domains
|
|
15
15
|
|
|
16
|
-
# @return [Array<Pin::
|
|
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
|
-
|
|
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
|
data/lib/solargraph/equality.rb
CHANGED
data/lib/solargraph/gem_pins.rb
CHANGED
|
@@ -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,14 @@ 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
|
-
|
|
28
|
+
# @type [Pin::Method, nil]
|
|
29
|
+
combined_pin = nil
|
|
30
|
+
# @param memo [Pin::Method, nil]
|
|
31
|
+
# @param pin [Pin::Method]
|
|
32
|
+
out = pins.reduce(combined_pin) do |memo, pin|
|
|
35
33
|
next pin if memo.nil?
|
|
36
34
|
if memo == pin && memo.source != :combined
|
|
37
35
|
# @todo we should track down situations where we are handled
|
|
@@ -45,8 +43,19 @@ module Solargraph
|
|
|
45
43
|
out
|
|
46
44
|
end
|
|
47
45
|
|
|
46
|
+
# @param yard_plugins [Array<String>] The names of YARD plugins to use.
|
|
47
|
+
# @param gemspec [Gem::Specification]
|
|
48
|
+
# @return [Array<Pin::Base>]
|
|
49
|
+
def self.build_yard_pins(yard_plugins, gemspec)
|
|
50
|
+
Yardoc.cache(yard_plugins, gemspec) unless Yardoc.cached?(gemspec)
|
|
51
|
+
return [] unless Yardoc.cached?(gemspec)
|
|
52
|
+
yardoc = Yardoc.load!(gemspec)
|
|
53
|
+
YardMap::Mapper.new(yardoc, gemspec).map
|
|
54
|
+
end
|
|
55
|
+
|
|
48
56
|
# @param yard_pins [Array<Pin::Base>]
|
|
49
|
-
# @param
|
|
57
|
+
# @param rbs_pins [Array<Pin::Base>]
|
|
58
|
+
#
|
|
50
59
|
# @return [Array<Pin::Base>]
|
|
51
60
|
def self.combine(yard_pins, rbs_pins)
|
|
52
61
|
in_yard = Set.new
|
|
@@ -57,6 +66,7 @@ module Solargraph
|
|
|
57
66
|
next yard_pin unless rbs_pin && yard_pin.class == Pin::Method
|
|
58
67
|
|
|
59
68
|
unless rbs_pin
|
|
69
|
+
# @sg-ignore https://github.com/castwide/solargraph/pull/1114
|
|
60
70
|
logger.debug { "GemPins.combine: No rbs pin for #{yard_pin.path} - using YARD's '#{yard_pin.inspect} (return_type=#{yard_pin.return_type}; signatures=#{yard_pin.signatures})" }
|
|
61
71
|
next yard_pin
|
|
62
72
|
end
|
|
@@ -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|
|