solargraph 0.54.4 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/linting.yml +125 -0
- data/.github/workflows/plugins.yml +149 -5
- data/.github/workflows/rspec.yml +39 -4
- data/.github/workflows/typecheck.yml +8 -3
- data/.gitignore +7 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +2627 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +104 -0
- data/README.md +20 -6
- data/Rakefile +125 -13
- data/lib/solargraph/api_map/cache.rb +3 -2
- data/lib/solargraph/api_map/constants.rb +218 -0
- data/lib/solargraph/api_map/index.rb +44 -42
- data/lib/solargraph/api_map/source_to_yard.rb +10 -4
- data/lib/solargraph/api_map/store.rb +165 -32
- data/lib/solargraph/api_map.rb +319 -243
- data/lib/solargraph/bench.rb +18 -1
- data/lib/solargraph/complex_type/type_methods.rb +7 -1
- data/lib/solargraph/complex_type/unique_type.rb +105 -16
- data/lib/solargraph/complex_type.rb +40 -7
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +20 -3
- 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 +61 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
- data/lib/solargraph/convention/struct_definition.rb +164 -0
- data/lib/solargraph/convention.rb +35 -4
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
- data/lib/solargraph/doc_map.rb +313 -65
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/gem_pins.rb +60 -38
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +13 -7
- data/lib/solargraph/language_server/host.rb +14 -3
- data/lib/solargraph/language_server/message/base.rb +2 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -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 +1 -0
- data/lib/solargraph/library.rb +53 -32
- data/lib/solargraph/location.rb +23 -0
- data/lib/solargraph/logging.rb +12 -2
- data/lib/solargraph/page.rb +4 -0
- data/lib/solargraph/parser/comment_ripper.rb +20 -7
- data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
- data/lib/solargraph/parser/node_methods.rb +16 -2
- data/lib/solargraph/parser/node_processor/base.rb +10 -5
- data/lib/solargraph/parser/node_processor.rb +26 -9
- data/lib/solargraph/parser/parser_gem/class_methods.rb +17 -15
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
- data/lib/solargraph/parser/parser_gem/node_methods.rb +8 -4
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +63 -30
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
- data/lib/solargraph/parser/region.rb +4 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +1 -0
- data/lib/solargraph/pin/base.rb +360 -30
- data/lib/solargraph/pin/base_variable.rb +16 -10
- data/lib/solargraph/pin/block.rb +2 -0
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +83 -3
- data/lib/solargraph/pin/closure.rb +20 -1
- data/lib/solargraph/pin/common.rb +10 -1
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/delegated_method.rb +21 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +18 -6
- data/lib/solargraph/pin/method.rb +175 -46
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/namespace.rb +17 -9
- data/lib/solargraph/pin/parameter.rb +78 -19
- data/lib/solargraph/pin/proxy_type.rb +13 -6
- data/lib/solargraph/pin/reference/override.rb +24 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +26 -0
- data/lib/solargraph/pin/search.rb +3 -1
- data/lib/solargraph/pin/signature.rb +44 -0
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +8 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/pin_cache.rb +245 -0
- data/lib/solargraph/position.rb +11 -0
- data/lib/solargraph/range.rb +10 -0
- data/lib/solargraph/rbs_map/conversions.rb +226 -70
- data/lib/solargraph/rbs_map/core_fills.rb +32 -16
- data/lib/solargraph/rbs_map/core_map.rb +37 -11
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +88 -18
- data/lib/solargraph/shell.rb +20 -18
- data/lib/solargraph/source/chain/array.rb +11 -7
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +53 -23
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/hash.rb +4 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +12 -1
- data/lib/solargraph/source/chain/literal.rb +22 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +84 -47
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +2 -3
- data/lib/solargraph/source/source_chainer.rb +3 -3
- data/lib/solargraph/source.rb +5 -2
- data/lib/solargraph/source_map/clip.rb +4 -2
- data/lib/solargraph/source_map/data.rb +4 -0
- data/lib/solargraph/source_map/mapper.rb +13 -7
- data/lib/solargraph/source_map.rb +21 -31
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +8 -0
- data/lib/solargraph/type_checker.rb +208 -128
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/workspace/config.rb +1 -3
- data/lib/solargraph/workspace/require_paths.rb +98 -0
- data/lib/solargraph/workspace.rb +38 -52
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
- data/lib/solargraph/yard_map/mapper.rb +4 -3
- data/lib/solargraph/yard_map/to_method.rb +4 -2
- data/lib/solargraph/yardoc.rb +22 -10
- data/lib/solargraph.rb +34 -1
- data/rbs/fills/tuple.rbs +149 -0
- data/rbs_collection.yaml +19 -0
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -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 +15 -4
- metadata +157 -15
- data/lib/.rubocop.yml +0 -22
- data/lib/solargraph/cache.rb +0 -77
@@ -17,7 +17,13 @@ module Solargraph
|
|
17
17
|
@word = word
|
18
18
|
end
|
19
19
|
|
20
|
-
# @sg-ignore
|
20
|
+
# @sg-ignore two problems - Declared return type
|
21
|
+
# ::Solargraph::Source::Chain::Array does not match inferred
|
22
|
+
# type ::Array(::Class<::Solargraph::Source::Chain::Link>,
|
23
|
+
# ::String) for
|
24
|
+
# Solargraph::Source::Chain::Link#equality_fields
|
25
|
+
# and
|
26
|
+
# Not enough arguments to Module#protected
|
21
27
|
protected def equality_fields
|
22
28
|
[self.class, word]
|
23
29
|
end
|
@@ -39,6 +45,7 @@ module Solargraph
|
|
39
45
|
end
|
40
46
|
|
41
47
|
# debugging description of contents; not for machine use
|
48
|
+
# @return [String]
|
42
49
|
def desc
|
43
50
|
word
|
44
51
|
end
|
@@ -74,6 +81,8 @@ module Solargraph
|
|
74
81
|
end
|
75
82
|
|
76
83
|
# debugging description of contents; not for machine use
|
84
|
+
#
|
85
|
+
# @return [String]
|
77
86
|
def desc
|
78
87
|
word
|
79
88
|
end
|
@@ -82,6 +91,8 @@ module Solargraph
|
|
82
91
|
"#<#{self.class} - `#{self.desc}`>"
|
83
92
|
end
|
84
93
|
|
94
|
+
include Logging
|
95
|
+
|
85
96
|
protected
|
86
97
|
|
87
98
|
# Mark whether this link is the head of a chain
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'parser'
|
4
|
+
|
3
5
|
module Solargraph
|
4
6
|
class Source
|
5
7
|
class Chain
|
@@ -8,9 +10,22 @@ module Solargraph
|
|
8
10
|
@word ||= "<#{@type}>"
|
9
11
|
end
|
10
12
|
|
13
|
+
attr_reader :value
|
14
|
+
|
11
15
|
# @param type [String]
|
12
|
-
|
16
|
+
# @param node [Parser::AST::Node, Object]
|
17
|
+
def initialize type, node
|
18
|
+
if node.is_a?(::Parser::AST::Node)
|
19
|
+
if node.type == :true
|
20
|
+
@value = true
|
21
|
+
elsif node.type == :false
|
22
|
+
@value = false
|
23
|
+
elsif [:int, :sym].include?(node.type)
|
24
|
+
@value = node.children.first
|
25
|
+
end
|
26
|
+
end
|
13
27
|
@type = type
|
28
|
+
@literal_type = ComplexType.try_parse(@value.inspect)
|
14
29
|
@complex_type = ComplexType.try_parse(type)
|
15
30
|
end
|
16
31
|
|
@@ -20,7 +35,12 @@ module Solargraph
|
|
20
35
|
end
|
21
36
|
|
22
37
|
def resolve api_map, name_pin, locals
|
23
|
-
|
38
|
+
if api_map.super_and_sub?(@complex_type.name, @literal_type.name)
|
39
|
+
[Pin::ProxyType.anonymous(@literal_type, source: :chain)]
|
40
|
+
else
|
41
|
+
# we don't support this value as a literal type
|
42
|
+
[Pin::ProxyType.anonymous(@complex_type, source: :chain)]
|
43
|
+
end
|
24
44
|
end
|
25
45
|
end
|
26
46
|
end
|
@@ -15,7 +15,7 @@ module Solargraph
|
|
15
15
|
|
16
16
|
def resolve api_map, name_pin, locals
|
17
17
|
types = @links.map { |link| link.infer(api_map, name_pin, locals) }
|
18
|
-
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq))]
|
18
|
+
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq), source: :chain)]
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -15,7 +15,7 @@ module Solargraph
|
|
15
15
|
# @param with_block [Boolean] True if the chain is inside a block
|
16
16
|
# @param head [Boolean] True if the call is the start of its chain
|
17
17
|
def initialize word, with_block = false
|
18
|
-
super(word, [], with_block)
|
18
|
+
super(word, nil, [], with_block)
|
19
19
|
end
|
20
20
|
|
21
21
|
# @param api_map [ApiMap]
|
@@ -15,6 +15,7 @@ module Solargraph
|
|
15
15
|
#
|
16
16
|
class Chain
|
17
17
|
include Equality
|
18
|
+
include Logging
|
18
19
|
|
19
20
|
autoload :Link, 'solargraph/source/chain/link'
|
20
21
|
autoload :Call, 'solargraph/source/chain/call'
|
@@ -39,7 +40,7 @@ module Solargraph
|
|
39
40
|
@@inference_invalidation_key = nil
|
40
41
|
@@inference_cache = {}
|
41
42
|
|
42
|
-
UNDEFINED_CALL = Chain::Call.new('<undefined>')
|
43
|
+
UNDEFINED_CALL = Chain::Call.new('<undefined>', nil)
|
43
44
|
UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
|
44
45
|
|
45
46
|
# @return [::Array<Source::Chain::Link>]
|
@@ -76,15 +77,28 @@ module Solargraph
|
|
76
77
|
# Determine potential Pins returned by this chain of words
|
77
78
|
#
|
78
79
|
# @param api_map [ApiMap]
|
79
|
-
# @param name_pin [Pin::Closure] the surrounding closure pin for
|
80
|
-
# the statement represented by this chain for type resolution
|
81
|
-
# and method pin lookup.
|
82
80
|
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
81
|
+
# @param name_pin [Pin::Base] A pin
|
82
|
+
# representing the place in which expression is evaluated (e.g.,
|
83
|
+
# a Method pin, or a Module or Class pin if not run within a
|
84
|
+
# method - both in terms of the closure around the chain, as well
|
85
|
+
# as the self type used for any method calls in head position.
|
86
|
+
#
|
87
|
+
# Requirements for name_pin:
|
88
|
+
#
|
89
|
+
# * name_pin.context: This should be a type representing the
|
90
|
+
# namespace where we can look up non-local variables and
|
91
|
+
# method names. If it is a Class<X>, we will look up
|
92
|
+
# :class scoped methods/variables.
|
86
93
|
#
|
87
|
-
#
|
94
|
+
# * name_pin.binder: Used for method call lookups only
|
95
|
+
# (Chain::Call links). For method calls as the first
|
96
|
+
# element in the chain, 'name_pin.binder' should be the
|
97
|
+
# same as name_pin.context above. For method calls later
|
98
|
+
# in the chain (e.g., 'b' in a.b.c), it should represent
|
99
|
+
# 'a'.
|
100
|
+
#
|
101
|
+
# @param locals [::Array<Pin::LocalVariable>] Any local
|
88
102
|
# variables / method parameters etc visible by the statement
|
89
103
|
#
|
90
104
|
# @return [::Array<Pin::Base>] Pins representing possible return
|
@@ -101,16 +115,25 @@ module Solargraph
|
|
101
115
|
working_pin = name_pin
|
102
116
|
links[0..-2].each do |link|
|
103
117
|
pins = link.resolve(api_map, working_pin, locals)
|
104
|
-
type =
|
105
|
-
|
106
|
-
|
118
|
+
type = infer_from_definitions(pins, working_pin, api_map, locals)
|
119
|
+
if type.undefined?
|
120
|
+
logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) => [] - undefined type from #{link.desc}" }
|
121
|
+
return []
|
122
|
+
end
|
123
|
+
# We continue to use the context from the head pin, in case
|
124
|
+
# we need it to, for instance, provide context for a block
|
125
|
+
# evaluation. However, we use the last link's return type
|
126
|
+
# for the binder, as this is chaining off of it, and the
|
127
|
+
# binder is now the lhs of the rhs we are evaluating.
|
128
|
+
working_pin = Pin::ProxyType.anonymous(name_pin.context, binder: type, closure: name_pin, source: :chain)
|
129
|
+
logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) - after processing #{link.desc}, new working_pin=#{working_pin} with binder #{working_pin.binder}" }
|
107
130
|
end
|
108
131
|
links.last.last_context = working_pin
|
109
132
|
links.last.resolve(api_map, working_pin, locals)
|
110
133
|
end
|
111
134
|
|
112
135
|
# @param api_map [ApiMap]
|
113
|
-
# @param name_pin [Pin::Base]
|
136
|
+
# @param name_pin [Pin::Base] The pin for the closure in which this code runs
|
114
137
|
# @param locals [::Array<Pin::LocalVariable>]
|
115
138
|
# @return [ComplexType]
|
116
139
|
# @sg-ignore
|
@@ -123,7 +146,7 @@ module Solargraph
|
|
123
146
|
@@inference_invalidation_key = api_map.hash
|
124
147
|
@@inference_cache = {}
|
125
148
|
end
|
126
|
-
out = infer_uncached
|
149
|
+
out = infer_uncached(api_map, name_pin, locals).downcast_to_literal_if_possible
|
127
150
|
logger.debug { "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}" }
|
128
151
|
@@inference_cache[cache_key] = out
|
129
152
|
end
|
@@ -134,8 +157,14 @@ module Solargraph
|
|
134
157
|
# @return [ComplexType]
|
135
158
|
def infer_uncached api_map, name_pin, locals
|
136
159
|
pins = define(api_map, name_pin, locals)
|
137
|
-
|
138
|
-
|
160
|
+
if pins.empty?
|
161
|
+
logger.debug { "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}) => undefined - no pins" }
|
162
|
+
return ComplexType::UNDEFINED
|
163
|
+
end
|
164
|
+
type = infer_from_definitions(pins, links.last.last_context, api_map, locals)
|
165
|
+
out = maybe_nil(type)
|
166
|
+
logger.debug { "Chain#infer_uncached(links=#{self.links.map(&:desc)}, locals=#{locals.map(&:desc)}, name_pin=#{name_pin}, name_pin.closure=#{name_pin.closure.inspect}, name_pin.binder=#{name_pin.binder}) => #{out.rooted_tags.inspect}" }
|
167
|
+
out
|
139
168
|
end
|
140
169
|
|
141
170
|
# @return [Boolean]
|
@@ -166,6 +195,7 @@ module Solargraph
|
|
166
195
|
|
167
196
|
include Logging
|
168
197
|
|
198
|
+
# @return [String]
|
169
199
|
def desc
|
170
200
|
links.map(&:desc).to_s
|
171
201
|
end
|
@@ -174,6 +204,8 @@ module Solargraph
|
|
174
204
|
desc
|
175
205
|
end
|
176
206
|
|
207
|
+
include Logging
|
208
|
+
|
177
209
|
private
|
178
210
|
|
179
211
|
# @param pins [::Array<Pin::Base>]
|
@@ -181,8 +213,10 @@ module Solargraph
|
|
181
213
|
# @param api_map [ApiMap]
|
182
214
|
# @param locals [::Enumerable<Pin::LocalVariable>]
|
183
215
|
# @return [ComplexType]
|
184
|
-
def
|
185
|
-
|
216
|
+
def infer_from_definitions pins, context, api_map, locals
|
217
|
+
# @type [::Array<ComplexType>]
|
218
|
+
types = []
|
219
|
+
unresolved_pins = []
|
186
220
|
# @todo this param tag shouldn't be needed to probe the type
|
187
221
|
# @todo ...but given it is needed, typecheck should complain that it is needed
|
188
222
|
# @param pin [Pin::Base]
|
@@ -200,42 +234,45 @@ module Solargraph
|
|
200
234
|
# that accepts only [Pin::Namespace] as an argument
|
201
235
|
type = type.resolve_generics(pin.closure, context.binder)
|
202
236
|
end
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
end
|
237
|
+
types << type
|
238
|
+
else
|
239
|
+
unresolved_pins << pin
|
207
240
|
end
|
208
241
|
end
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
@@inference_stack.pop
|
222
|
-
if type.defined?
|
223
|
-
possibles.push type
|
224
|
-
break if pin.is_a?(Pin::Method)
|
225
|
-
end
|
242
|
+
|
243
|
+
# Limit method inference recursion
|
244
|
+
if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
|
245
|
+
return ComplexType::UNDEFINED
|
246
|
+
end
|
247
|
+
|
248
|
+
@@inference_depth += 1
|
249
|
+
# @param pin [Pin::Base]
|
250
|
+
unresolved_pins.each do |pin|
|
251
|
+
# Avoid infinite recursion
|
252
|
+
if @@inference_stack.include?(pin.identity)
|
253
|
+
next
|
226
254
|
end
|
227
|
-
|
255
|
+
|
256
|
+
@@inference_stack.push(pin.identity)
|
257
|
+
type = pin.probe(api_map)
|
258
|
+
@@inference_stack.pop
|
259
|
+
types.push type if type
|
228
260
|
end
|
229
|
-
|
261
|
+
@@inference_depth -= 1
|
230
262
|
|
231
|
-
type = if
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
263
|
+
type = if types.empty?
|
264
|
+
ComplexType::UNDEFINED
|
265
|
+
elsif types.length > 1
|
266
|
+
# Move nil to the end by convention
|
267
|
+
sorted = types.flat_map(&:items).sort { |a, _| a.tag == 'nil' ? 1 : 0 }
|
268
|
+
ComplexType.new(sorted.uniq)
|
269
|
+
else
|
270
|
+
ComplexType.new(types)
|
271
|
+
end
|
272
|
+
if context.nil? || context.return_type.undefined?
|
273
|
+
# up to downstream to resolve self type
|
274
|
+
return type
|
237
275
|
end
|
238
|
-
return type if context.nil? || context.return_type.undefined?
|
239
276
|
|
240
277
|
type.self_to_type(context.return_type)
|
241
278
|
end
|
@@ -28,7 +28,7 @@ module Solargraph
|
|
28
28
|
# syntax errors will be repaired.
|
29
29
|
# @return [String] The updated text.
|
30
30
|
def write text, nullable = false
|
31
|
-
if nullable and !range.nil? and new_text.match(/[
|
31
|
+
if nullable and !range.nil? and new_text.match(/[.\[{(@$:]$/)
|
32
32
|
[':', '@'].each do |dupable|
|
33
33
|
next unless new_text == dupable
|
34
34
|
offset = Position.to_offset(text, range.start)
|
@@ -59,7 +59,7 @@ module Solargraph
|
|
59
59
|
else
|
60
60
|
result = commit text, fixed
|
61
61
|
off = Position.to_offset(text, range.start)
|
62
|
-
match = result[0, off].match(/[
|
62
|
+
match = result[0, off].match(/[.:]+\z/)
|
63
63
|
if match
|
64
64
|
result = result[0, off].sub(/#{match[0]}\z/, ' ' * match[0].length) + result[off..-1]
|
65
65
|
end
|
@@ -35,7 +35,6 @@ module Solargraph
|
|
35
35
|
# The part of the word before the current position. Given the text
|
36
36
|
# `foo.bar`, the start_of_word at position(0, 6) is `ba`.
|
37
37
|
#
|
38
|
-
# @sg-ignore Improve resolution of String#match below
|
39
38
|
# @return [String]
|
40
39
|
def start_of_word
|
41
40
|
@start_of_word ||= begin
|
@@ -125,7 +124,7 @@ module Solargraph
|
|
125
124
|
def node_position
|
126
125
|
@node_position ||= begin
|
127
126
|
if start_of_word.empty?
|
128
|
-
match = source.code[0, offset].match(
|
127
|
+
match = source.code[0, offset].match(/\s*(\.|:+)\s*$/)
|
129
128
|
if match
|
130
129
|
Position.from_offset(source.code, offset - match[0].length)
|
131
130
|
else
|
@@ -160,7 +159,7 @@ module Solargraph
|
|
160
159
|
#
|
161
160
|
# @return [Regexp]
|
162
161
|
def end_word_pattern
|
163
|
-
/^([a-z0-9_]|[^\u0000-\u007F])*[
|
162
|
+
/^([a-z0-9_]|[^\u0000-\u007F])*[?!]?/i
|
164
163
|
end
|
165
164
|
end
|
166
165
|
end
|
@@ -32,8 +32,8 @@ module Solargraph
|
|
32
32
|
# @return [Source::Chain]
|
33
33
|
def chain
|
34
34
|
# Special handling for files that end with an integer and a period
|
35
|
-
return Chain.new([Chain::Literal.new('Integer'), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
|
36
|
-
return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
|
35
|
+
return Chain.new([Chain::Literal.new('Integer', Integer(phrase[0..-2])), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
|
36
|
+
return Chain.new([Chain::Literal.new('Symbol', phrase[1..].to_sym)]) if phrase.start_with?(':') && !phrase.start_with?('::')
|
37
37
|
return SourceChainer.chain(source, Position.new(position.line, position.character + 1)) if end_of_phrase.strip == '::' && source.code[Position.to_offset(source.code, position)].to_s.match?(/[a-z]/i)
|
38
38
|
begin
|
39
39
|
return Chain.new([]) if phrase.end_with?('..')
|
@@ -97,7 +97,7 @@ module Solargraph
|
|
97
97
|
# @return [String]
|
98
98
|
def end_of_phrase
|
99
99
|
@end_of_phrase ||= begin
|
100
|
-
match = phrase.match(
|
100
|
+
match = phrase.match(/\s*(\.{1}|::)\s*$/)
|
101
101
|
if match
|
102
102
|
match[0]
|
103
103
|
else
|
data/lib/solargraph/source.rb
CHANGED
@@ -30,7 +30,7 @@ module Solargraph
|
|
30
30
|
@node
|
31
31
|
end
|
32
32
|
|
33
|
-
# @return [Hash{Integer =>
|
33
|
+
# @return [Hash{Integer => Solargraph::Parser::Snippet}]
|
34
34
|
def comments
|
35
35
|
finalize
|
36
36
|
@comments
|
@@ -235,6 +235,7 @@ module Solargraph
|
|
235
235
|
# @return [Hash{Integer => String}]
|
236
236
|
def associated_comments
|
237
237
|
@associated_comments ||= begin
|
238
|
+
# @type [Hash{Integer => String}]
|
238
239
|
result = {}
|
239
240
|
buffer = String.new('')
|
240
241
|
# @type [Integer, nil]
|
@@ -317,7 +318,7 @@ module Solargraph
|
|
317
318
|
@string_nodes ||= string_nodes_in(node)
|
318
319
|
end
|
319
320
|
|
320
|
-
# @return [Array<Range>]
|
321
|
+
# @return [Array<Solargraph::Range>]
|
321
322
|
def comment_ranges
|
322
323
|
@comment_ranges ||= comments.values.map(&:range)
|
323
324
|
end
|
@@ -386,6 +387,7 @@ module Solargraph
|
|
386
387
|
# @return [Integer]
|
387
388
|
attr_writer :version
|
388
389
|
|
390
|
+
# @return [void]
|
389
391
|
def finalize
|
390
392
|
return if @finalized && changes.empty?
|
391
393
|
|
@@ -440,6 +442,7 @@ module Solargraph
|
|
440
442
|
# @return [String]
|
441
443
|
attr_writer :repaired
|
442
444
|
|
445
|
+
# @return [String]
|
443
446
|
def repaired
|
444
447
|
finalize
|
445
448
|
@repaired
|
@@ -11,7 +11,9 @@ module Solargraph
|
|
11
11
|
def initialize api_map, cursor
|
12
12
|
@api_map = api_map
|
13
13
|
@cursor = cursor
|
14
|
-
|
14
|
+
block_pin = block
|
15
|
+
block_pin.rebind(api_map) if block_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(block_pin.receiver).contain?(cursor.range.start)
|
16
|
+
@in_block = nil
|
15
17
|
end
|
16
18
|
|
17
19
|
# @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
|
@@ -63,7 +65,7 @@ module Solargraph
|
|
63
65
|
# position. Locals can be local variables, method parameters, or block
|
64
66
|
# parameters. The array starts with the nearest local pin.
|
65
67
|
#
|
66
|
-
# @return [::Array<Solargraph::Pin::
|
68
|
+
# @return [::Array<Solargraph::Pin::LocalVariable>]
|
67
69
|
def locals
|
68
70
|
@locals ||= source_map.locals_at(location)
|
69
71
|
end
|
@@ -3,15 +3,18 @@
|
|
3
3
|
module Solargraph
|
4
4
|
class SourceMap
|
5
5
|
class Data
|
6
|
+
# @param source [Solargraph::Source]
|
6
7
|
def initialize source
|
7
8
|
@source = source
|
8
9
|
end
|
9
10
|
|
11
|
+
# @return [Array<Solargraph::Pin::Base>]
|
10
12
|
def pins
|
11
13
|
generate
|
12
14
|
@pins || []
|
13
15
|
end
|
14
16
|
|
17
|
+
# @return [Array<Solargraph::LocalVariable>]
|
15
18
|
def locals
|
16
19
|
generate
|
17
20
|
@locals || []
|
@@ -19,6 +22,7 @@ module Solargraph
|
|
19
22
|
|
20
23
|
private
|
21
24
|
|
25
|
+
# @return [void]
|
22
26
|
def generate
|
23
27
|
return if @generated
|
24
28
|
|
@@ -41,7 +41,7 @@ module Solargraph
|
|
41
41
|
s = Position.new(0, 0)
|
42
42
|
e = Position.from_offset(code, code.length)
|
43
43
|
location = Location.new(filename, Range.new(s, e))
|
44
|
-
[[Pin::Namespace.new(location: location, name: '')], []]
|
44
|
+
[[Pin::Namespace.new(location: location, name: '', source: :source_map)], []]
|
45
45
|
end
|
46
46
|
|
47
47
|
class << self
|
@@ -55,6 +55,7 @@ module Solargraph
|
|
55
55
|
|
56
56
|
# @return [Array<Solargraph::Pin::Base>]
|
57
57
|
def pins
|
58
|
+
# @type [Array<Solargraph::Pin::Base>]
|
58
59
|
@pins ||= []
|
59
60
|
end
|
60
61
|
|
@@ -69,6 +70,7 @@ module Solargraph
|
|
69
70
|
# @param comment [String]
|
70
71
|
# @return [void]
|
71
72
|
def process_comment source_position, comment_position, comment
|
73
|
+
# @sg-ignore Wrong argument type for String#=~: object expected String::_MatchAgainst<String, undefined>, received Regexp
|
72
74
|
return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
|
73
75
|
cmnt = remove_inline_comment_hashes(comment)
|
74
76
|
parse = Solargraph::Source.parse_docstring(cmnt)
|
@@ -140,7 +142,8 @@ module Solargraph
|
|
140
142
|
scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
|
141
143
|
visibility: :public,
|
142
144
|
explicit: false,
|
143
|
-
attribute: true
|
145
|
+
attribute: true,
|
146
|
+
source: :source_map
|
144
147
|
)
|
145
148
|
end
|
146
149
|
if t.nil? || t.include?('w')
|
@@ -151,16 +154,17 @@ module Solargraph
|
|
151
154
|
comments: docstring.all.to_s,
|
152
155
|
scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
|
153
156
|
visibility: :public,
|
154
|
-
attribute: true
|
157
|
+
attribute: true,
|
158
|
+
source: :source_map
|
155
159
|
)
|
156
160
|
pins.push method_pin
|
157
|
-
method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
161
|
+
method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last, source: :source_map)
|
158
162
|
if pins.last.return_type.defined?
|
159
163
|
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
|
160
164
|
end
|
161
165
|
end
|
162
166
|
when 'visibility'
|
163
|
-
|
167
|
+
|
164
168
|
kind = directive.tag.text&.to_sym
|
165
169
|
return unless [:private, :protected, :public].include?(kind)
|
166
170
|
|
@@ -179,7 +183,7 @@ module Solargraph
|
|
179
183
|
pin.instance_variable_set(:@visibility, kind)
|
180
184
|
end
|
181
185
|
end
|
182
|
-
|
186
|
+
|
183
187
|
when 'parse'
|
184
188
|
begin
|
185
189
|
ns = closure_at(source_position)
|
@@ -205,7 +209,8 @@ module Solargraph
|
|
205
209
|
namespace = closure_at(source_position) || Pin::ROOT_PIN
|
206
210
|
namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
|
207
211
|
when 'override'
|
208
|
-
pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags
|
212
|
+
pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags,
|
213
|
+
source: :source_map)
|
209
214
|
when 'macro'
|
210
215
|
# @todo Handle macros
|
211
216
|
end
|
@@ -240,6 +245,7 @@ module Solargraph
|
|
240
245
|
|
241
246
|
# @return [void]
|
242
247
|
def process_comment_directives
|
248
|
+
# @sg-ignore Wrong argument type for String#=~: object expected String::_MatchAgainst<String, undefined>, received Regexp
|
243
249
|
return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
|
244
250
|
code_lines = @code.lines
|
245
251
|
@source.associated_comments.each do |line, comments|
|
@@ -21,6 +21,11 @@ module Solargraph
|
|
21
21
|
data.pins
|
22
22
|
end
|
23
23
|
|
24
|
+
# @return [Array<Pin::Base>]
|
25
|
+
def all_pins
|
26
|
+
pins + convention_pins
|
27
|
+
end
|
28
|
+
|
24
29
|
# @return [Array<Pin::LocalVariable>]
|
25
30
|
def locals
|
26
31
|
data.locals
|
@@ -30,13 +35,18 @@ module Solargraph
|
|
30
35
|
def initialize source
|
31
36
|
@source = source
|
32
37
|
|
33
|
-
|
34
|
-
|
38
|
+
conventions_environ.merge Convention.for_local(self) unless filename.nil?
|
39
|
+
# FIXME: unmemoizing the document_symbols in case it was called and memoized from any of conventions above
|
40
|
+
# this is to ensure that the convention_pins from all conventions are used in the document_symbols.
|
41
|
+
# solargraph-rails is known to use this method to get the document symbols. It should probably be removed.
|
42
|
+
@document_symbols = nil
|
43
|
+
self.convention_pins = conventions_environ.pins
|
35
44
|
@pin_select_cache = {}
|
36
45
|
end
|
37
46
|
|
38
|
-
# @
|
39
|
-
# @
|
47
|
+
# @generic T
|
48
|
+
# @param klass [Class<generic<T>>]
|
49
|
+
# @return [Array<generic<T>>]
|
40
50
|
def pins_by_class klass
|
41
51
|
@pin_select_cache[klass] ||= pin_class_hash.select { |key, _| key <= klass }.values.flatten
|
42
52
|
end
|
@@ -67,8 +77,8 @@ module Solargraph
|
|
67
77
|
end
|
68
78
|
|
69
79
|
# @return [Environ]
|
70
|
-
def
|
71
|
-
@
|
80
|
+
def conventions_environ
|
81
|
+
@conventions_environ ||= Environ.new
|
72
82
|
end
|
73
83
|
|
74
84
|
# all pins except Solargraph::Pin::Reference::Reference
|
@@ -118,23 +128,6 @@ module Solargraph
|
|
118
128
|
_locate_pin line, character, Pin::Namespace, Pin::Method, Pin::Block
|
119
129
|
end
|
120
130
|
|
121
|
-
# @todo Candidate for deprecation
|
122
|
-
#
|
123
|
-
# @param other_map [SourceMap]
|
124
|
-
# @return [Boolean]
|
125
|
-
def try_merge! other_map
|
126
|
-
return false if pins.length != other_map.pins.length || locals.length != other_map.locals.length || requires.map(&:name).uniq.sort != other_map.requires.map(&:name).uniq.sort
|
127
|
-
|
128
|
-
pins.each_index do |i|
|
129
|
-
return false unless pins[i].try_merge!(other_map.pins[i])
|
130
|
-
end
|
131
|
-
locals.each_index do |i|
|
132
|
-
return false unless locals[i].try_merge!(other_map.locals[i])
|
133
|
-
end
|
134
|
-
@source = other_map.source
|
135
|
-
true
|
136
|
-
end
|
137
|
-
|
138
131
|
# @param name [String]
|
139
132
|
# @return [Array<Location>]
|
140
133
|
def references name
|
@@ -175,10 +168,15 @@ module Solargraph
|
|
175
168
|
|
176
169
|
private
|
177
170
|
|
171
|
+
# @return [Hash{Class => Array<Pin::Base>}]
|
172
|
+
# @return [Array<Pin::Base>]
|
173
|
+
attr_writer :convention_pins
|
174
|
+
|
178
175
|
def pin_class_hash
|
179
176
|
@pin_class_hash ||= pins.to_set.classify(&:class).transform_values(&:to_a)
|
180
177
|
end
|
181
178
|
|
179
|
+
# @return [Data]
|
182
180
|
def data
|
183
181
|
@data ||= Data.new(source)
|
184
182
|
end
|
@@ -188,14 +186,6 @@ module Solargraph
|
|
188
186
|
@convention_pins || []
|
189
187
|
end
|
190
188
|
|
191
|
-
# @param pins [Array<Pin::Base>]
|
192
|
-
# @return [Array<Pin::Base>]
|
193
|
-
def convention_pins=(pins)
|
194
|
-
# unmemoizing the document_symbols in case it was called from any of conventions
|
195
|
-
@document_symbols = nil
|
196
|
-
@convention_pins = pins
|
197
|
-
end
|
198
|
-
|
199
189
|
# @param line [Integer]
|
200
190
|
# @param character [Integer]
|
201
191
|
# @param klasses [Array<Class>]
|
@@ -50,6 +50,8 @@ module Solargraph
|
|
50
50
|
# @param inferred [ComplexType]
|
51
51
|
# @return [Boolean]
|
52
52
|
def any_types_match? api_map, expected, inferred
|
53
|
+
expected = expected.downcast_to_literal_if_possible
|
54
|
+
inferred = inferred.downcast_to_literal_if_possible
|
53
55
|
return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
|
54
56
|
# walk through the union expected type and see if any members
|
55
57
|
# of the union match the inferred type
|
@@ -71,6 +73,8 @@ module Solargraph
|
|
71
73
|
# @param expected [ComplexType]
|
72
74
|
# @return [Boolean]
|
73
75
|
def all_types_match? api_map, inferred, expected
|
76
|
+
expected = expected.downcast_to_literal_if_possible
|
77
|
+
inferred = inferred.downcast_to_literal_if_possible
|
74
78
|
return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
|
75
79
|
inferred.each do |inf|
|
76
80
|
next if inf.duck_type?
|