solargraph 0.17.4 → 0.18.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/lib/solargraph.rb +16 -12
- data/lib/solargraph/api_map.rb +516 -588
- data/lib/solargraph/api_map/completion.rb +16 -0
- data/lib/solargraph/api_map/source_to_yard.rb +2 -2
- data/lib/solargraph/language_server.rb +12 -0
- data/lib/solargraph/language_server/completion_item_kinds.rb +31 -0
- data/lib/solargraph/language_server/error_codes.rb +16 -0
- data/lib/solargraph/language_server/host.rb +305 -0
- data/lib/solargraph/language_server/message.rb +70 -0
- data/lib/solargraph/language_server/message/base.rb +64 -0
- data/lib/solargraph/language_server/message/cancel_request.rb +11 -0
- data/lib/solargraph/language_server/message/client.rb +5 -0
- data/lib/solargraph/language_server/message/client/register_capability.rb +13 -0
- data/lib/solargraph/language_server/message/completion_item.rb +9 -0
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +23 -0
- data/lib/solargraph/language_server/message/exit_notification.rb +12 -0
- data/lib/solargraph/language_server/message/extended.rb +15 -0
- data/lib/solargraph/language_server/message/extended/document.rb +18 -0
- data/lib/solargraph/language_server/message/extended/search.rb +18 -0
- data/lib/solargraph/language_server/message/initialize.rb +39 -0
- data/lib/solargraph/language_server/message/initialized.rb +10 -0
- data/lib/solargraph/language_server/message/method_not_found.rb +14 -0
- data/lib/solargraph/language_server/message/method_not_implemented.rb +12 -0
- data/lib/solargraph/language_server/message/shutdown.rb +11 -0
- data/lib/solargraph/language_server/message/text_document.rb +21 -0
- data/lib/solargraph/language_server/message/text_document/base.rb +17 -0
- data/lib/solargraph/language_server/message/text_document/completion.rb +69 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +38 -0
- data/lib/solargraph/language_server/message/text_document/did_change.rb +15 -0
- data/lib/solargraph/language_server/message/text_document/did_close.rb +12 -0
- data/lib/solargraph/language_server/message/text_document/did_open.rb +13 -0
- data/lib/solargraph/language_server/message/text_document/did_save.rb +15 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +31 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +36 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +19 -0
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +29 -0
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +23 -0
- data/lib/solargraph/language_server/message/workspace.rb +11 -0
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +9 -0
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +30 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +31 -0
- data/lib/solargraph/language_server/symbol_kinds.rb +32 -0
- data/lib/solargraph/language_server/transport.rb +7 -0
- data/lib/solargraph/language_server/transport/socket.rb +66 -0
- data/lib/solargraph/language_server/uri_helpers.rb +21 -0
- data/lib/solargraph/library.rb +225 -0
- data/lib/solargraph/live_map.rb +1 -1
- data/lib/solargraph/page.rb +61 -0
- data/lib/solargraph/pin.rb +7 -0
- data/lib/solargraph/pin/attribute.rb +9 -0
- data/lib/solargraph/pin/base.rb +76 -6
- data/lib/solargraph/pin/base_variable.rb +29 -7
- data/lib/solargraph/pin/block_parameter.rb +53 -0
- data/lib/solargraph/pin/constant.rb +6 -2
- data/lib/solargraph/pin/conversions.rb +65 -0
- data/lib/solargraph/pin/directed/attribute.rb +4 -0
- data/lib/solargraph/pin/directed/method.rb +6 -1
- data/lib/solargraph/pin/helper.rb +35 -0
- data/lib/solargraph/pin/keyword.rb +22 -0
- data/lib/solargraph/pin/local_variable.rb +0 -1
- data/lib/solargraph/pin/method.rb +55 -2
- data/lib/solargraph/pin/method_parameter.rb +19 -0
- data/lib/solargraph/pin/namespace.rb +7 -2
- data/lib/solargraph/pin/parameter.rb +23 -0
- data/lib/solargraph/pin/plugin/method.rb +3 -2
- data/lib/solargraph/pin/yard_object.rb +101 -0
- data/lib/solargraph/server.rb +82 -135
- data/lib/solargraph/shell.rb +20 -1
- data/lib/solargraph/source.rb +709 -0
- data/lib/solargraph/source/flawed_builder.rb +10 -0
- data/lib/solargraph/source/fragment.rb +319 -0
- data/lib/solargraph/source/position.rb +26 -0
- data/lib/solargraph/source/range.rb +39 -0
- data/lib/solargraph/suggestion.rb +29 -4
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +105 -0
- data/lib/solargraph/{api_map → workspace}/config.rb +1 -1
- data/lib/solargraph/yard_map.rb +59 -37
- metadata +168 -5
- data/lib/solargraph/api_map/source.rb +0 -470
- data/lib/solargraph/code_map.rb +0 -868
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ccb588fb1b726e174fc3e8d569a92f1e8ae0c9d
|
4
|
+
data.tar.gz: 0ec8f37bcd32ecde24d4f56a80bd6db81d559c13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71df1903bd21f4a7e762068d23ff09c5d5c1a078e63eec46ce04b5500d9e27fcda2ff8a921c16ce3a4b7d6379cc8ac582ea48a9d36fc6e4f1e8ed8282d9e77fa
|
7
|
+
data.tar.gz: 4e1fe48e17648c06a5ca4bf513fc46856ae848746844a1db6f2d21ee281f8c664a44ddbf7b1dd01e47ec80abbb8eba77c742853086a1d43d66e7a9b218c21a12
|
data/lib/solargraph.rb
CHANGED
@@ -3,18 +3,22 @@ require 'rubygems/package'
|
|
3
3
|
require 'yard-solargraph'
|
4
4
|
|
5
5
|
module Solargraph
|
6
|
-
autoload :Shell,
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :NodeMethods,
|
10
|
-
autoload :Suggestion,
|
11
|
-
autoload :Server,
|
12
|
-
autoload :YardMap,
|
13
|
-
autoload :Pin,
|
14
|
-
autoload :LiveMap,
|
15
|
-
autoload :ServerMethods,
|
16
|
-
autoload :Plugin,
|
17
|
-
autoload :CoreFills,
|
6
|
+
autoload :Shell, 'solargraph/shell'
|
7
|
+
autoload :Source, 'solargraph/source'
|
8
|
+
autoload :ApiMap, 'solargraph/api_map'
|
9
|
+
autoload :NodeMethods, 'solargraph/node_methods'
|
10
|
+
autoload :Suggestion, 'solargraph/suggestion'
|
11
|
+
autoload :Server, 'solargraph/server'
|
12
|
+
autoload :YardMap, 'solargraph/yard_map'
|
13
|
+
autoload :Pin, 'solargraph/pin'
|
14
|
+
autoload :LiveMap, 'solargraph/live_map'
|
15
|
+
autoload :ServerMethods, 'solargraph/server_methods'
|
16
|
+
autoload :Plugin, 'solargraph/plugin'
|
17
|
+
autoload :CoreFills, 'solargraph/core_fills'
|
18
|
+
autoload :LanguageServer, 'solargraph/language_server'
|
19
|
+
autoload :Workspace, 'solargraph/workspace'
|
20
|
+
autoload :Page, 'solargraph/page'
|
21
|
+
autoload :Library, 'solargraph/library'
|
18
22
|
|
19
23
|
YARDOC_PATH = File.join(File.realpath(File.dirname(__FILE__)), '..', 'yardoc')
|
20
24
|
YARD_EXTENSION_FILE = File.join(File.realpath(File.dirname(__FILE__)), 'yard-solargraph.rb')
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -1,67 +1,37 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'parser/current'
|
3
|
-
require 'thread'
|
4
2
|
require 'set'
|
3
|
+
require 'time'
|
5
4
|
|
6
5
|
module Solargraph
|
7
6
|
class ApiMap
|
8
|
-
autoload :Config, 'solargraph/api_map/config'
|
9
|
-
autoload :Source, 'solargraph/api_map/source'
|
10
7
|
autoload :Cache, 'solargraph/api_map/cache'
|
11
8
|
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
12
|
-
|
9
|
+
autoload :Completion, 'solargraph/api_map/completion'
|
13
10
|
|
14
11
|
include NodeMethods
|
15
12
|
include Solargraph::ApiMap::SourceToYard
|
16
13
|
include CoreFills
|
17
14
|
|
18
|
-
# The
|
19
|
-
# additional files to parse and analyze.
|
15
|
+
# The workspace to analyze and process.
|
20
16
|
#
|
21
|
-
# @return [
|
17
|
+
# @return [Solargraph::Workspace]
|
22
18
|
attr_reader :workspace
|
23
19
|
|
24
|
-
# @param workspace [
|
20
|
+
# @param workspace [Solargraph::Workspace]
|
25
21
|
def initialize workspace = nil
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
# @todo Deprecate strings for the workspace parameter
|
23
|
+
workspace = Solargraph::Workspace.new(workspace) if workspace.kind_of?(String)
|
24
|
+
workspace = Solargraph::Workspace.new(nil) if workspace.nil?
|
25
|
+
@workspace = workspace
|
29
26
|
require_extensions
|
30
|
-
unless @workspace.nil?
|
31
|
-
workspace_files.concat config.calculated
|
32
|
-
workspace_files.each do |wf|
|
33
|
-
begin
|
34
|
-
@@source_cache[wf] ||= Source.load(wf)
|
35
|
-
rescue Parser::SyntaxError, EncodingError => e
|
36
|
-
STDERR.puts "Failed to load #{wf}: #{e.message}"
|
37
|
-
@@source_cache[wf] = Source.virtual('', wf)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
@sources = {}
|
42
27
|
@virtual_source = nil
|
43
|
-
@virtual_filename = nil
|
44
|
-
@stale = true
|
45
28
|
@yard_stale = true
|
46
|
-
|
29
|
+
process_maps
|
47
30
|
yard_map
|
48
31
|
end
|
49
32
|
|
50
|
-
|
51
|
-
|
52
|
-
# if it exists.
|
53
|
-
#
|
54
|
-
# @return [Solargraph::ApiMap::Config]
|
55
|
-
def config reload = false
|
56
|
-
@config = ApiMap::Config.new(@workspace) if @config.nil? or reload
|
57
|
-
@config
|
58
|
-
end
|
59
|
-
|
60
|
-
# An array of all workspace files included in the map.
|
61
|
-
#
|
62
|
-
# @return[Array<String>]
|
63
|
-
def workspace_files
|
64
|
-
@workspace_files ||= []
|
33
|
+
def self.load directory
|
34
|
+
self.new(Solargraph::Workspace.new(directory))
|
65
35
|
end
|
66
36
|
|
67
37
|
# An array of required paths in the workspace.
|
@@ -71,67 +41,81 @@ module Solargraph
|
|
71
41
|
@required ||= []
|
72
42
|
end
|
73
43
|
|
74
|
-
# Get a YardMap associated with the current
|
44
|
+
# Get a YardMap associated with the current workspace.
|
75
45
|
#
|
76
46
|
# @return [Solargraph::YardMap]
|
77
47
|
def yard_map
|
78
|
-
refresh
|
48
|
+
# refresh
|
79
49
|
if @yard_map.nil? || @yard_map.required.to_set != required.to_set
|
80
50
|
@yard_map = Solargraph::YardMap.new(required: required, workspace: workspace)
|
81
51
|
end
|
82
52
|
@yard_map
|
83
53
|
end
|
84
54
|
|
85
|
-
# Get a LiveMap associated with the current
|
55
|
+
# Get a LiveMap associated with the current workspace.
|
86
56
|
#
|
87
57
|
# @return [Solargraph::LiveMap]
|
88
58
|
def live_map
|
89
59
|
@live_map ||= Solargraph::LiveMap.new(self)
|
90
60
|
end
|
91
61
|
|
92
|
-
#
|
93
|
-
#
|
62
|
+
# Declare a virtual source that will be included in the map regardless of
|
63
|
+
# whether it's in the workspace.
|
94
64
|
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
true
|
105
|
-
end
|
106
|
-
end
|
107
|
-
if filename.nil? or filename.end_with?('.rb') or filename.end_with?('.erb')
|
108
|
-
eliminate @virtual_filename unless @virtual_source.nil? or @virtual_filename == filename or workspace_files.include?(@virtual_filename)
|
109
|
-
@virtual_filename = filename
|
110
|
-
@virtual_source = Source.fix(code, filename, cursor)
|
111
|
-
unless filename.nil? or workspace_files.include?(filename)
|
112
|
-
current_files = @workspace_files
|
113
|
-
@workspace_files = config(true).calculated
|
114
|
-
(current_files - @workspace_files).each { |f| eliminate f }
|
115
|
-
end
|
116
|
-
process_virtual
|
65
|
+
# If the source is in the workspace, virtualizing it has no effect. Only
|
66
|
+
# one source can be virtualized at a time.
|
67
|
+
#
|
68
|
+
# @param [Solargraph::Source]
|
69
|
+
def virtualize source
|
70
|
+
eliminate @virtual_source unless @virtual_source.nil?
|
71
|
+
if workspace.has_source?(source)
|
72
|
+
@sources = workspace.sources
|
73
|
+
@virtual_source = nil
|
117
74
|
else
|
118
|
-
|
119
|
-
|
75
|
+
@virtual_source = source
|
76
|
+
@sources = workspace.sources
|
77
|
+
unless @virtual_source.nil?
|
78
|
+
@sources.push @virtual_source
|
79
|
+
process_virtual
|
120
80
|
end
|
121
81
|
end
|
122
|
-
@virtual_source
|
123
82
|
end
|
124
83
|
|
125
|
-
# @
|
126
|
-
def append_source code, filename
|
127
|
-
|
84
|
+
# @todo Candidate for deprecation
|
85
|
+
def append_source code, filename = nil
|
86
|
+
source = Source.load_string(code, filename)
|
87
|
+
virtualize source
|
128
88
|
end
|
129
89
|
|
130
90
|
# Refresh the ApiMap.
|
131
91
|
#
|
132
92
|
# @param force [Boolean] Perform a refresh even if the map is not "stale."
|
133
93
|
def refresh force = false
|
134
|
-
|
94
|
+
return unless @force or changed?
|
95
|
+
if force
|
96
|
+
process_maps
|
97
|
+
else
|
98
|
+
current_workspace_sources.reject{|s| workspace.sources.include?(s)}.each do |source|
|
99
|
+
eliminate source
|
100
|
+
end
|
101
|
+
@sources = workspace.sources
|
102
|
+
@sources.push @virtual_source unless @virtual_source.nil?
|
103
|
+
cache.clear
|
104
|
+
namespace_map.clear
|
105
|
+
@sources.each do |s|
|
106
|
+
s.namespace_nodes.each_pair do |k, v|
|
107
|
+
namespace_map[k] ||= []
|
108
|
+
namespace_map[k].concat v
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@sources.each do |source|
|
112
|
+
if @stime.nil? or source.stime > @stime
|
113
|
+
eliminate source
|
114
|
+
map_source source
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
@stime = Time.new
|
135
119
|
end
|
136
120
|
|
137
121
|
# True if a workspace file has been created, modified, or deleted since
|
@@ -139,15 +123,10 @@ module Solargraph
|
|
139
123
|
#
|
140
124
|
# @return [Boolean]
|
141
125
|
def changed?
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
current.each do |f|
|
147
|
-
if !File.exist?(f) or File.mtime(f) != source_file_mtime(f)
|
148
|
-
return true
|
149
|
-
end
|
150
|
-
end
|
126
|
+
return true if current_workspace_sources.length != workspace.sources.length
|
127
|
+
return true if @stime.nil?
|
128
|
+
return true if workspace.stime > @stime
|
129
|
+
return true if !@virtual_source.nil? and @virtual_source.stime > @stime
|
151
130
|
false
|
152
131
|
end
|
153
132
|
|
@@ -156,17 +135,17 @@ module Solargraph
|
|
156
135
|
# @param node [AST::Node]
|
157
136
|
# @return [YARD::Docstring]
|
158
137
|
def get_docstring_for node
|
159
|
-
|
160
|
-
return nil if
|
161
|
-
|
138
|
+
source = get_source_for(node)
|
139
|
+
return nil if source.nil?
|
140
|
+
source.docstring_for(node)
|
162
141
|
end
|
163
142
|
|
164
143
|
# An array of suggestions based on Ruby keywords (`if`, `end`, etc.).
|
165
144
|
#
|
166
|
-
# @return [Array<Solargraph::
|
145
|
+
# @return [Array<Solargraph::Pin::Keyword>]
|
167
146
|
def self.keywords
|
168
147
|
@keyword_suggestions ||= KEYWORDS.map{ |s|
|
169
|
-
|
148
|
+
Pin::Keyword.new(s)
|
170
149
|
}.freeze
|
171
150
|
end
|
172
151
|
|
@@ -174,7 +153,7 @@ module Solargraph
|
|
174
153
|
#
|
175
154
|
# @return [Array<String>]
|
176
155
|
def namespaces
|
177
|
-
refresh
|
156
|
+
# refresh
|
178
157
|
namespace_map.keys
|
179
158
|
end
|
180
159
|
|
@@ -203,8 +182,9 @@ module Solargraph
|
|
203
182
|
#
|
204
183
|
# @param namespace [String] The namespace to match
|
205
184
|
# @param context [String] The context to search
|
206
|
-
# @return [Array<Solargraph::
|
185
|
+
# @return [Array<Solargraph::Pin::Base>]
|
207
186
|
def get_constants namespace, context = ''
|
187
|
+
namespace ||= ''
|
208
188
|
skip = []
|
209
189
|
result = []
|
210
190
|
if context.empty?
|
@@ -222,7 +202,19 @@ module Solargraph
|
|
222
202
|
parts.pop
|
223
203
|
end
|
224
204
|
end
|
225
|
-
result.map{|pin| Suggestion.pull(pin)}
|
205
|
+
# result.map{|pin| Suggestion.pull(pin)}
|
206
|
+
result
|
207
|
+
end
|
208
|
+
|
209
|
+
def find_fully_qualified_type namespace_type, context_type = ''
|
210
|
+
namespace, scope = extract_namespace_and_scope(namespace_type)
|
211
|
+
context = extract_namespace(context_type)
|
212
|
+
fqns = find_fully_qualified_namespace(namespace, context)
|
213
|
+
subtypes = get_subtypes(namespace_type)
|
214
|
+
fqns = "#{fqns}<#{subtypes.join(', ')}>" unless subtypes.empty?
|
215
|
+
return fqns if scope == :instance
|
216
|
+
type = get_namespace_type(fqns)
|
217
|
+
"#{type == :class ? 'Class<' : 'Module<'}#{fqns}>"
|
226
218
|
end
|
227
219
|
|
228
220
|
# Get a fully qualified namespace name. This method will start the search
|
@@ -232,7 +224,8 @@ module Solargraph
|
|
232
224
|
# @param root [String] The context to search
|
233
225
|
# @return [String]
|
234
226
|
def find_fully_qualified_namespace name, root = '', skip = []
|
235
|
-
refresh
|
227
|
+
# refresh
|
228
|
+
return nil if name.nil?
|
236
229
|
return nil if skip.include?(root)
|
237
230
|
skip.push root
|
238
231
|
if name == ''
|
@@ -244,11 +237,14 @@ module Solargraph
|
|
244
237
|
else
|
245
238
|
if (root == '')
|
246
239
|
return name unless namespace_map[name].nil?
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
240
|
+
im = @namespace_includes['']
|
241
|
+
unless im.nil?
|
242
|
+
im.each do |i|
|
243
|
+
reroot = "#{root == '' ? '' : root + '::'}#{i}"
|
244
|
+
recname = find_fully_qualified_namespace name.to_s, reroot, skip
|
245
|
+
return recname unless recname.nil?
|
246
|
+
end
|
247
|
+
end
|
252
248
|
else
|
253
249
|
roots = root.to_s.split('::')
|
254
250
|
while roots.length > 0
|
@@ -257,10 +253,13 @@ module Solargraph
|
|
257
253
|
roots.pop
|
258
254
|
end
|
259
255
|
return name unless namespace_map[name].nil?
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
256
|
+
im = @namespace_includes['']
|
257
|
+
unless im.nil?
|
258
|
+
im.each do |i|
|
259
|
+
recname = find_fully_qualified_namespace name, i, skip
|
260
|
+
return recname unless recname.nil?
|
261
|
+
end
|
262
|
+
end
|
264
263
|
end
|
265
264
|
end
|
266
265
|
result = yard_map.find_fully_qualified_namespace(name, root)
|
@@ -277,134 +276,71 @@ module Solargraph
|
|
277
276
|
# @param scope [Symbol] :instance or :class
|
278
277
|
# @return [Array<Solargraph::Pin::InstanceVariable>]
|
279
278
|
def get_instance_variable_pins(namespace, scope = :instance)
|
280
|
-
|
281
|
-
(@ivar_pins[namespace] || []).select{ |pin| pin.scope == scope }
|
279
|
+
suggest_unique_variables (@ivar_pins[namespace] || []).select{ |pin| pin.scope == scope }
|
282
280
|
end
|
283
281
|
|
284
|
-
# Get an array of
|
285
|
-
# namespace and scope.
|
282
|
+
# Get an array of class variable pins for a namespace.
|
286
283
|
#
|
287
284
|
# @param namespace [String] A fully qualified namespace
|
288
|
-
# @param scope [Symbol] :instance or :class
|
289
|
-
# @return [Array<Solargraph::Suggestion>]
|
290
|
-
def get_instance_variables(namespace, scope = :instance)
|
291
|
-
refresh
|
292
|
-
result = []
|
293
|
-
ip = @ivar_pins[namespace]
|
294
|
-
unless ip.nil?
|
295
|
-
result.concat suggest_unique_variables(ip.select{ |pin| pin.scope == scope })
|
296
|
-
end
|
297
|
-
result
|
298
|
-
end
|
299
|
-
|
300
285
|
# @return [Array<Solargraph::Pin::ClassVariable>]
|
301
286
|
def get_class_variable_pins(namespace)
|
302
|
-
|
303
|
-
@cvar_pins[namespace] || []
|
304
|
-
end
|
305
|
-
|
306
|
-
# @return [Array<Solargraph::Suggestion>]
|
307
|
-
def get_class_variables(namespace)
|
308
|
-
refresh
|
309
|
-
result = []
|
310
|
-
cp = @cvar_pins[namespace]
|
311
|
-
unless cp.nil?
|
312
|
-
result.concat suggest_unique_variables(cp)
|
313
|
-
end
|
314
|
-
result
|
287
|
+
suggest_unique_variables(@cvar_pins[namespace] || [])
|
315
288
|
end
|
316
289
|
|
317
|
-
# @return [Array<Solargraph::Pin::
|
290
|
+
# @return [Array<Solargraph::Pin::Base>]
|
318
291
|
def get_symbols
|
319
|
-
refresh
|
320
|
-
@symbol_pins
|
292
|
+
# refresh
|
293
|
+
@symbol_pins
|
321
294
|
end
|
322
295
|
|
323
296
|
# @return [String]
|
324
297
|
def get_filename_for(node)
|
325
|
-
@sources.each do |
|
298
|
+
@sources.each do |source|
|
326
299
|
return source.filename if source.include?(node)
|
327
300
|
end
|
328
301
|
nil
|
329
302
|
end
|
330
303
|
|
331
|
-
# @return [Solargraph::
|
304
|
+
# @return [Solargraph::Source]
|
332
305
|
def get_source_for(node)
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
nil
|
337
|
-
end
|
338
|
-
|
339
|
-
# @return [String]
|
340
|
-
def infer_instance_variable(var, namespace, scope)
|
341
|
-
refresh
|
342
|
-
pins = @ivar_pins[namespace]
|
343
|
-
return nil if pins.nil?
|
344
|
-
pin = pins.select{|p| p.name == var and p.scope == scope}.first
|
345
|
-
return nil if pin.nil?
|
346
|
-
type = nil
|
347
|
-
type = find_fully_qualified_namespace(pin.return_type, pin.namespace) unless pin.return_type.nil?
|
348
|
-
if type.nil?
|
349
|
-
zparts = resolve_node_signature(pin.assignment_node).split('.')
|
350
|
-
ztype = infer_signature_type(zparts[0..-2].join('.'), namespace, scope: :instance, call_node: pin.assignment_node)
|
351
|
-
type = get_return_type_from_macro(ztype, zparts[-1], pin.assignment_node, :instance, [:public, :private, :protected])
|
306
|
+
matches = []
|
307
|
+
@sources.each do |source|
|
308
|
+
matches.push source if source.include?(node)
|
352
309
|
end
|
353
|
-
|
354
|
-
end
|
355
|
-
|
356
|
-
# @return [String]
|
357
|
-
def infer_class_variable(var, namespace)
|
358
|
-
refresh
|
359
|
-
fqns = find_fully_qualified_namespace(namespace)
|
360
|
-
pins = @cvar_pins[fqns]
|
361
|
-
return nil if pins.nil?
|
362
|
-
pin = pins.select{|p| p.name == var}.first
|
363
|
-
return nil if pin.nil? or pin.return_type.nil?
|
364
|
-
find_fully_qualified_namespace(pin.return_type, pin.namespace)
|
365
|
-
end
|
366
|
-
|
367
|
-
# @return [Array<Solargraph::Suggestion>]
|
368
|
-
def get_global_variables
|
369
|
-
globals = []
|
370
|
-
@sources.values.each do |s|
|
371
|
-
globals.concat s.global_variable_pins
|
372
|
-
end
|
373
|
-
suggest_unique_variables globals
|
310
|
+
matches.first
|
374
311
|
end
|
375
312
|
|
376
313
|
# @return [Array<Solargraph::Pin::GlobalVariable>]
|
377
314
|
def get_global_variable_pins
|
378
315
|
globals = []
|
379
|
-
@sources.
|
316
|
+
@sources.each do |s|
|
380
317
|
globals.concat s.global_variable_pins
|
381
318
|
end
|
382
319
|
globals
|
383
320
|
end
|
384
321
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
if
|
393
|
-
|
394
|
-
# Avoid infinite loops from variable assignments that reference themselves
|
395
|
-
return nil if node.children[name_i].to_s == sig.split('.').first
|
396
|
-
type = infer_signature_type(sig, namespace, call_node: node.children[sig_i])
|
397
|
-
end
|
398
|
-
cache.set_assignment_node_type(node, namespace, type)
|
399
|
-
type
|
322
|
+
def get_type_methods type, context = ''
|
323
|
+
return [] if type.nil?
|
324
|
+
namespace, scope = extract_namespace_and_scope(type)
|
325
|
+
base = extract_namespace(context)
|
326
|
+
fqns = find_fully_qualified_namespace(namespace, base)
|
327
|
+
return [] if fqns.nil?
|
328
|
+
visibility = [:public]
|
329
|
+
visibility.push :private, :protected if fqns == base
|
330
|
+
get_methods fqns, scope: scope, visibility: visibility
|
400
331
|
end
|
401
332
|
|
402
|
-
def
|
403
|
-
return [] unless node.type == :send
|
333
|
+
def get_methods fqns, scope: :instance, visibility: [:public], deep: true
|
404
334
|
result = []
|
405
|
-
|
406
|
-
|
335
|
+
if fqns == ''
|
336
|
+
skip = []
|
337
|
+
result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
|
338
|
+
result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
|
339
|
+
result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
|
340
|
+
else
|
341
|
+
result.concat inner_get_methods(fqns, scope, visibility, deep, [])
|
407
342
|
end
|
343
|
+
# result.each{|pin| pin.resolve(self)}
|
408
344
|
result
|
409
345
|
end
|
410
346
|
|
@@ -419,222 +355,199 @@ module Solargraph
|
|
419
355
|
# @param scope [Symbol] :class or :instance
|
420
356
|
# @return [String]
|
421
357
|
def infer_signature_type signature, namespace, scope: :class, call_node: nil
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
fqns = find_fully_qualified_namespace(signature, namespace)
|
431
|
-
unless fqns.nil? or fqns.empty?
|
432
|
-
type = (get_namespace_type(fqns) == :class ? 'Class' : 'Module')
|
433
|
-
return "#{type}<#{fqns}>"
|
358
|
+
return nil if signature.start_with?('.')
|
359
|
+
# inner_infer_signature_type signature, namespace, scope, call_node, true
|
360
|
+
base, rest = signature.split('.', 2)
|
361
|
+
if base == 'self'
|
362
|
+
if rest.nil?
|
363
|
+
combine_type(namespace, scope)
|
364
|
+
else
|
365
|
+
inner_infer_signature_type(rest, namespace, scope, call_node, false)
|
434
366
|
end
|
435
|
-
end
|
436
|
-
result = nil
|
437
|
-
if namespace.end_with?('#class')
|
438
|
-
result = infer_signature_type signature, namespace[0..-7], scope: (scope == :class ? :instance : :class), call_node: call_node
|
439
367
|
else
|
440
|
-
|
441
|
-
if
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
368
|
+
pins = infer_signature_pins(base, namespace, scope, call_node)
|
369
|
+
return nil if pins.empty?
|
370
|
+
pin = pins.first
|
371
|
+
if rest.nil?
|
372
|
+
pin.resolve self
|
373
|
+
pin.return_type
|
374
|
+
elsif pin.signature.nil? or pin.signature.empty?
|
375
|
+
if pin.path.nil?
|
376
|
+
pin.resolve self
|
377
|
+
fqtype = find_fully_qualified_type(pin.return_type, namespace)
|
378
|
+
return nil if fqtype.nil?
|
379
|
+
subns, subsc = extract_namespace_and_scope(fqtype)
|
380
|
+
inner_infer_signature_type(rest, subns, subsc, call_node, true)
|
452
381
|
else
|
453
|
-
|
382
|
+
inner_infer_signature_type(rest, pin.path, scope, call_node, true)
|
454
383
|
end
|
455
384
|
else
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
type = inner_infer_signature_type(parts[0], namespace, scope: scope, call_node: call_node)
|
460
|
-
if parts.length < 2
|
461
|
-
if type.nil? and !parts.length.nil?
|
462
|
-
path = "#{clean_namespace_string(namespace)}#{scope == :class ? '.' : '#'}#{parts[0]}"
|
463
|
-
subtypes = get_subtypes(namespace)
|
464
|
-
type = subtypes[0] if METHODS_RETURNING_SUBTYPES.include?(path)
|
465
|
-
end
|
466
|
-
result = type
|
467
|
-
else
|
468
|
-
result = inner_infer_signature_type(parts[1], type, scope: :instance, call_node: call_node)
|
469
|
-
end
|
470
|
-
else
|
471
|
-
result = inner_infer_signature_type(parts[1], type, scope: :class, call_node: call_node)
|
472
|
-
end
|
473
|
-
result = type if result == 'self'
|
385
|
+
subtype = inner_infer_signature_type(pin.signature, namespace, scope, call_node, true)
|
386
|
+
subns, subsc = extract_namespace_and_scope(subtype)
|
387
|
+
inner_infer_signature_type(rest, subns, subsc, call_node, false)
|
474
388
|
end
|
475
389
|
end
|
476
|
-
cache.set_signature_type signature, namespace, scope, result
|
477
|
-
result
|
478
390
|
end
|
479
391
|
|
480
|
-
#
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
end
|
494
|
-
type
|
495
|
-
end
|
496
|
-
|
497
|
-
# Get an array of singleton methods that are available in the specified
|
498
|
-
# namespace.
|
499
|
-
#
|
500
|
-
# @return [Array<Solargraph::Suggestion>]
|
501
|
-
def get_methods(namespace, root = '', visibility: [:public])
|
502
|
-
refresh
|
503
|
-
namespace = clean_namespace_string(namespace)
|
504
|
-
fqns = find_fully_qualified_namespace(namespace, root)
|
505
|
-
meths = []
|
506
|
-
skip = []
|
507
|
-
meths.concat inner_get_methods(namespace, root, skip, visibility)
|
508
|
-
yard_meths = yard_map.get_methods(fqns, '', visibility: visibility)
|
509
|
-
if yard_meths.any?
|
510
|
-
meths.concat yard_meths
|
511
|
-
else
|
512
|
-
type = get_namespace_type(fqns)
|
513
|
-
if type == :class
|
514
|
-
meths.concat yard_map.get_instance_methods('Class')
|
392
|
+
# @return [ApiMap::Completion]
|
393
|
+
def complete fragment
|
394
|
+
return Completion.new([], fragment.whole_word_range) if fragment.string? or fragment.comment?
|
395
|
+
result = []
|
396
|
+
if fragment.base.empty?
|
397
|
+
if fragment.signature.start_with?('@@')
|
398
|
+
result.concat get_class_variable_pins(fragment.namespace)
|
399
|
+
elsif fragment.signature.start_with?('@')
|
400
|
+
result.concat get_instance_variable_pins(fragment.namespace, fragment.scope)
|
401
|
+
elsif fragment.signature.start_with?('$')
|
402
|
+
result.concat get_global_variable_pins
|
403
|
+
elsif fragment.signature.start_with?(':') and !fragment.signature.start_with?('::')
|
404
|
+
result.concat get_symbols
|
515
405
|
else
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
unless news.empty?
|
521
|
-
if @method_pins[fqns]
|
522
|
-
inits = @method_pins[fqns].select{|p| p.name == 'initialize'}
|
523
|
-
meths -= news unless inits.empty?
|
524
|
-
inits.each do |pin|
|
525
|
-
meths.push Suggestion.new('new', kind: pin.kind, docstring: pin.docstring, detail: pin.namespace, arguments: pin.parameters, path: pin.path)
|
406
|
+
unless fragment.signature.include?('::')
|
407
|
+
result.concat fragment.local_variable_pins
|
408
|
+
result.concat get_type_methods(fragment.namespace, fragment.namespace)
|
409
|
+
result.concat ApiMap.keywords
|
526
410
|
end
|
411
|
+
result.concat get_constants(fragment.base, fragment.namespace)
|
527
412
|
end
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
413
|
+
else
|
414
|
+
if fragment.signature.include?('::') and !fragment.signature.include?('.')
|
415
|
+
result.concat get_constants(fragment.base, fragment.namespace)
|
416
|
+
else
|
417
|
+
type = infer_signature_type(fragment.base, fragment.namespace, scope: fragment.scope, call_node: fragment.node)
|
418
|
+
result.concat get_type_methods(type)
|
532
419
|
end
|
533
420
|
end
|
534
|
-
|
535
|
-
|
536
|
-
next if strings.include?(ls.to_s)
|
537
|
-
meths.push ls
|
538
|
-
end
|
539
|
-
meths
|
421
|
+
filtered = result.uniq(&:identifier).select{|s| s.kind != Solargraph::LanguageServer::CompletionItemKinds::METHOD or s.name.match(/^[a-z0-9_]*(\!|\?|=)?$/i)}.sort_by.with_index{ |x, idx| [x.name, idx] }
|
422
|
+
Completion.new(filtered, fragment.whole_word_range)
|
540
423
|
end
|
541
424
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
end
|
552
|
-
meths = []
|
553
|
-
meths += inner_get_instance_methods(namespace, root, [], visibility) #unless has_yardoc?
|
554
|
-
fqns = find_fully_qualified_namespace(namespace, root)
|
555
|
-
yard_meths = yard_map.get_instance_methods(fqns, '', visibility: visibility)
|
556
|
-
if yard_meths.any?
|
557
|
-
meths.concat yard_meths
|
558
|
-
else
|
559
|
-
type = get_namespace_type(fqns)
|
560
|
-
if type == :class
|
561
|
-
meths += yard_map.get_instance_methods('Object')
|
562
|
-
elsif type == :module
|
563
|
-
meths += yard_map.get_instance_methods('Module')
|
564
|
-
end
|
565
|
-
end
|
566
|
-
if namespace == '' and root == ''
|
567
|
-
config.domains.each do |d|
|
568
|
-
meths.concat get_instance_methods(d)
|
425
|
+
def define fragment
|
426
|
+
return [] if fragment.string? or fragment.comment?
|
427
|
+
pins = infer_signature_pins fragment.whole_signature, fragment.namespace, fragment.scope, fragment.node
|
428
|
+
return [] if pins.empty?
|
429
|
+
if pins.first.variable?
|
430
|
+
result = []
|
431
|
+
pins.select{|pin| pin.variable?}.each do |pin|
|
432
|
+
pin.resolve self
|
433
|
+
result.concat infer_signature_pins(pin.return_type, fragment.namespace, fragment.scope, fragment.node)
|
569
434
|
end
|
435
|
+
result
|
436
|
+
else
|
437
|
+
pins.reject{|pin| pin.path.nil?}
|
570
438
|
end
|
571
|
-
strings = meths.map(&:to_s)
|
572
|
-
live_map.get_methods(fqns, '', 'class', visibility.include?(:private)).each do |ls|
|
573
|
-
next if strings.include?(ls.to_s)
|
574
|
-
meths.push ls
|
575
|
-
end
|
576
|
-
meths
|
577
439
|
end
|
578
440
|
|
579
|
-
#
|
441
|
+
# Identify the variable, constant, or method call at the fragment's location.
|
580
442
|
#
|
581
|
-
# @param
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
443
|
+
# @param fragment [Solargraph::Source::Fragment]
|
444
|
+
# @return [Array<Solargraph::Pin::Base>]
|
445
|
+
def identify fragment
|
446
|
+
pins = infer_signature_pins(fragment.whole_signature, fragment.namespace, fragment.scope, fragment.node)
|
447
|
+
pins.each { |pin| pin.resolve self }
|
448
|
+
pins
|
449
|
+
end
|
450
|
+
|
451
|
+
def infer_signature_pins signature, namespace, scope, call_node
|
452
|
+
return [] if signature.nil? or signature.empty?
|
453
|
+
base, rest = signature.split('.', 2)
|
454
|
+
if base.start_with?('@@')
|
455
|
+
pin = get_class_variable_pins(namespace).select{|pin| pin.name == base}.first
|
456
|
+
return [] if pin.nil?
|
457
|
+
return [pin] if rest.nil?
|
458
|
+
fqns = find_fully_qualified_namespace(pin.return_type, namespace)
|
459
|
+
return [] if fqns.nil?
|
460
|
+
return inner_infer_signature_pins rest, namespace, scope, call_node, false
|
461
|
+
elsif base.start_with?('@')
|
462
|
+
pin = get_instance_variable_pins(namespace, scope).select{|pin| pin.name == base}.first
|
463
|
+
return [] if pin.nil?
|
464
|
+
pin.resolve self
|
465
|
+
return [pin] if rest.nil?
|
466
|
+
fqtype = find_fully_qualified_type(pin.return_type, namespace)
|
467
|
+
return [] if fqtype.nil?
|
468
|
+
subns, subsc = extract_namespace_and_scope(fqtype)
|
469
|
+
return inner_infer_signature_pins rest, subns, subsc, call_node, false
|
470
|
+
elsif base.start_with?('$')
|
471
|
+
# @todo globals
|
472
|
+
else
|
473
|
+
type = find_fully_qualified_namespace(base, namespace)
|
474
|
+
unless type.nil?
|
475
|
+
if rest.nil?
|
476
|
+
return get_path_suggestions(type)
|
477
|
+
else
|
478
|
+
return inner_infer_signature_pins rest, type, :class, call_node, false
|
479
|
+
end
|
588
480
|
end
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
481
|
+
source = get_source_for(call_node)
|
482
|
+
unless source.nil?
|
483
|
+
lvpins = source.local_variable_pins.select{|pin| pin.name == base and pin.visible_from?(call_node)}
|
484
|
+
unless lvpins.empty?
|
485
|
+
if rest.nil?
|
486
|
+
return lvpins
|
487
|
+
else
|
488
|
+
lvp = lvpins.first
|
489
|
+
lvp.resolve self
|
490
|
+
type = lvp.return_type
|
491
|
+
unless type.nil?
|
492
|
+
fqtype = find_fully_qualified_type(type, namespace)
|
493
|
+
return [] if fqtype.nil?
|
494
|
+
subns, subsc = extract_namespace_and_scope(fqtype)
|
495
|
+
return inner_infer_signature_pins(rest, subns, subsc, call_node, false)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
599
499
|
end
|
600
|
-
|
601
|
-
# @todo Finish refreshing the map
|
602
|
-
@workspace_files = config(true).calculated
|
500
|
+
return inner_infer_signature_pins signature, namespace, scope, call_node, true
|
603
501
|
end
|
604
502
|
end
|
605
503
|
|
606
|
-
#
|
504
|
+
# Get the namespace's type (Class or Module).
|
607
505
|
#
|
608
|
-
# @
|
609
|
-
|
610
|
-
|
506
|
+
# @param [String] A fully qualified namespace
|
507
|
+
# @return [Symbol] :class, :module, or nil
|
508
|
+
def get_namespace_type fqns
|
509
|
+
pin = @namespace_path_pins[fqns]
|
510
|
+
return yard_map.get_namespace_type(fqns) if pin.nil?
|
511
|
+
pin.first.type
|
512
|
+
end
|
513
|
+
|
514
|
+
def combine_type namespace, scope
|
515
|
+
if scope == :instance
|
516
|
+
namespace
|
517
|
+
else
|
518
|
+
type = get_namespace_type(namespace)
|
519
|
+
"#{type == :class ? 'Class' : 'Module'}<#{namespace}>"
|
520
|
+
end
|
611
521
|
end
|
612
522
|
|
613
523
|
# Get an array of all suggestions that match the specified path.
|
614
524
|
#
|
615
525
|
# @param path [String] The path to find
|
616
|
-
# @return [Array<Solargraph::
|
526
|
+
# @return [Array<Solargraph::Pin::Base>]
|
617
527
|
def get_path_suggestions path
|
618
|
-
|
528
|
+
return [] if path.nil?
|
529
|
+
# refresh
|
619
530
|
result = []
|
620
531
|
if path.include?('#')
|
621
532
|
# It's an instance method
|
622
533
|
parts = path.split('#')
|
623
|
-
result =
|
534
|
+
result = get_methods(parts[0], visibility: [:public, :private, :protected]).select{|s| s.name == parts[1]}
|
624
535
|
elsif path.include?('.')
|
625
536
|
# It's a class method
|
626
537
|
parts = path.split('.')
|
627
|
-
result = get_methods(parts[0],
|
538
|
+
result = get_methods(parts[0], scope: :class, visibility: [:public, :private, :protected]).select{|s| s.name == parts[1]}
|
628
539
|
else
|
629
540
|
# It's a class or module
|
630
541
|
parts = path.split('::')
|
631
542
|
np = @namespace_pins[parts[0..-2].join('::')]
|
632
543
|
unless np.nil?
|
633
|
-
result.concat np.select{|p| p.name == parts.last}
|
544
|
+
result.concat np.select{|p| p.name == parts.last}
|
634
545
|
end
|
635
546
|
result.concat yard_map.objects(path)
|
636
547
|
end
|
637
|
-
|
548
|
+
# @todo Resolve the pins?
|
549
|
+
result.map{|pin| pin.resolve(self); pin}
|
550
|
+
# result
|
638
551
|
end
|
639
552
|
|
640
553
|
# Get a list of documented paths that match the query.
|
@@ -645,8 +558,8 @@ module Solargraph
|
|
645
558
|
# @param query [String] The text to match
|
646
559
|
# @return [Array<String>]
|
647
560
|
def search query
|
648
|
-
refresh
|
649
|
-
rake_yard(@sources
|
561
|
+
# refresh
|
562
|
+
rake_yard(@sources) if @yard_stale
|
650
563
|
@yard_stale = false
|
651
564
|
found = []
|
652
565
|
code_object_paths.each do |k|
|
@@ -665,8 +578,8 @@ module Solargraph
|
|
665
578
|
# @param path [String] The path to find
|
666
579
|
# @return [Array<YARD::CodeObject::Base>]
|
667
580
|
def document path
|
668
|
-
refresh
|
669
|
-
rake_yard(@sources
|
581
|
+
# refresh
|
582
|
+
rake_yard(@sources) if @yard_stale
|
670
583
|
@yard_stale = false
|
671
584
|
docs = []
|
672
585
|
docs.push code_object_at(path) unless code_object_at(path).nil?
|
@@ -674,6 +587,31 @@ module Solargraph
|
|
674
587
|
docs
|
675
588
|
end
|
676
589
|
|
590
|
+
def query_symbols query
|
591
|
+
result = []
|
592
|
+
@sources.each do |s|
|
593
|
+
result.concat s.query_symbols(query)
|
594
|
+
end
|
595
|
+
result
|
596
|
+
end
|
597
|
+
|
598
|
+
def superclass_of fqns
|
599
|
+
found = @superclasses[fqns]
|
600
|
+
return nil if found.nil?
|
601
|
+
find_fully_qualified_namespace(found, fqns)
|
602
|
+
end
|
603
|
+
|
604
|
+
def locate_pin location
|
605
|
+
@sources.each do |source|
|
606
|
+
pin = source.locate_pin(location)
|
607
|
+
unless pin.nil?
|
608
|
+
pin.resolve self
|
609
|
+
return pin
|
610
|
+
end
|
611
|
+
end
|
612
|
+
nil
|
613
|
+
end
|
614
|
+
|
677
615
|
private
|
678
616
|
|
679
617
|
# @return [Hash]
|
@@ -681,15 +619,9 @@ module Solargraph
|
|
681
619
|
@namespace_map ||= {}
|
682
620
|
end
|
683
621
|
|
684
|
-
def clear
|
685
|
-
@stale = false
|
686
|
-
namespace_map.clear
|
687
|
-
path_macros.clear
|
688
|
-
@required = config.required.clone
|
689
|
-
end
|
690
|
-
|
691
622
|
def process_maps
|
692
|
-
|
623
|
+
@sources = workspace.sources
|
624
|
+
@sources.push @virtual_source unless @virtual_source.nil?
|
693
625
|
cache.clear
|
694
626
|
@ivar_pins = {}
|
695
627
|
@cvar_pins = {}
|
@@ -701,25 +633,22 @@ module Solargraph
|
|
701
633
|
@namespace_extends = {}
|
702
634
|
@superclasses = {}
|
703
635
|
@namespace_pins = {}
|
636
|
+
@namespace_path_pins = {}
|
704
637
|
namespace_map.clear
|
705
|
-
@required = config.required.clone
|
706
|
-
@
|
707
|
-
unless @virtual_source.nil?
|
708
|
-
@sources[@virtual_filename] = @virtual_source
|
709
|
-
end
|
710
|
-
@sources.values.each do |s|
|
638
|
+
@required = workspace.config.required.clone
|
639
|
+
@sources.each do |s|
|
711
640
|
s.namespace_nodes.each_pair do |k, v|
|
712
641
|
namespace_map[k] ||= []
|
713
642
|
namespace_map[k].concat v
|
714
643
|
end
|
715
644
|
end
|
716
|
-
@sources.
|
645
|
+
@sources.each do |s|
|
717
646
|
map_source s
|
718
|
-
|
647
|
+
end
|
719
648
|
@required.uniq!
|
720
649
|
live_map.refresh
|
721
|
-
@stale = false
|
722
650
|
@yard_stale = true
|
651
|
+
@stime = Time.now
|
723
652
|
end
|
724
653
|
|
725
654
|
def rebuild_local_yardoc
|
@@ -728,46 +657,30 @@ module Solargraph
|
|
728
657
|
Dir.chdir(workspace) { Process.spawn('yardoc') }
|
729
658
|
end
|
730
659
|
|
731
|
-
def process_workspace_files
|
732
|
-
@sources.clear
|
733
|
-
workspace_files.each do |f|
|
734
|
-
if File.file?(f)
|
735
|
-
begin
|
736
|
-
@@source_cache[f] ||= Source.load(f)
|
737
|
-
@sources[f] = @@source_cache[f]
|
738
|
-
rescue Exception => e
|
739
|
-
STDERR.puts "Failed to load #{f}: #{e.message}"
|
740
|
-
end
|
741
|
-
end
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
660
|
def process_virtual
|
746
661
|
unless @virtual_source.nil?
|
747
662
|
cache.clear
|
748
663
|
namespace_map.clear
|
749
|
-
@sources
|
750
|
-
@sources.values.each do |s|
|
664
|
+
@sources.each do |s|
|
751
665
|
s.namespace_nodes.each_pair do |k, v|
|
752
666
|
namespace_map[k] ||= []
|
753
667
|
namespace_map[k].concat v
|
754
668
|
end
|
755
669
|
end
|
756
|
-
eliminate @virtual_filename
|
757
670
|
map_source @virtual_source
|
758
671
|
end
|
759
672
|
end
|
760
673
|
|
761
|
-
def eliminate
|
674
|
+
def eliminate source
|
762
675
|
[@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values, @namespace_pins.values].each do |pinsets|
|
763
676
|
pinsets.each do |pins|
|
764
|
-
pins.delete_if{|pin| pin.filename == filename}
|
677
|
+
pins.delete_if{|pin| pin.filename == source.filename}
|
765
678
|
end
|
766
679
|
end
|
767
|
-
|
680
|
+
@symbol_pins.delete_if{|pin| pin.filename == source.filename}
|
768
681
|
end
|
769
682
|
|
770
|
-
# @param [Solargraph::
|
683
|
+
# @param [Solargraph::Source]
|
771
684
|
def map_source source
|
772
685
|
source.method_pins.each do |pin|
|
773
686
|
@method_pins[pin.namespace] ||= []
|
@@ -790,7 +703,7 @@ module Solargraph
|
|
790
703
|
@const_pins[pin.namespace].push pin
|
791
704
|
end
|
792
705
|
source.symbol_pins.each do |pin|
|
793
|
-
@symbol_pins.push
|
706
|
+
@symbol_pins.push pin
|
794
707
|
end
|
795
708
|
source.namespace_includes.each_pair do |ns, i|
|
796
709
|
@namespace_includes[ns || ''] ||= []
|
@@ -804,6 +717,8 @@ module Solargraph
|
|
804
717
|
@superclasses[cls] = sup
|
805
718
|
end
|
806
719
|
source.namespace_pins.each do |pin|
|
720
|
+
@namespace_path_pins[pin.path] ||= []
|
721
|
+
@namespace_path_pins[pin.path].push pin
|
807
722
|
@namespace_pins[pin.namespace] ||= []
|
808
723
|
@namespace_pins[pin.namespace].push pin
|
809
724
|
end
|
@@ -818,144 +733,60 @@ module Solargraph
|
|
818
733
|
@cache ||= Cache.new
|
819
734
|
end
|
820
735
|
|
821
|
-
def inner_get_methods
|
822
|
-
|
823
|
-
return
|
824
|
-
skip.push
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
unless
|
836
|
-
|
837
|
-
sc_visi.push :protected if root == fqns
|
838
|
-
nfqns = find_fully_qualified_namespace(sc, fqns)
|
839
|
-
meths.concat inner_get_methods('', nfqns, skip, sc_visi)
|
840
|
-
meths.concat yard_map.get_methods(nfqns, '', visibility: sc_visi)
|
841
|
-
end
|
842
|
-
end
|
843
|
-
em = @namespace_extends[fqns]
|
844
|
-
unless em.nil?
|
845
|
-
em.each do |e|
|
846
|
-
meths.concat get_instance_methods(e, fqns, visibility: visibility)
|
847
|
-
end
|
848
|
-
end
|
849
|
-
meths.concat get_instance_methods('', '', visibility: [:public])
|
850
|
-
meths.uniq
|
851
|
-
end
|
852
|
-
|
853
|
-
def inner_get_instance_methods(namespace, root, skip, visibility = [:public])
|
854
|
-
fqns = find_fully_qualified_namespace(namespace, root)
|
855
|
-
meths = []
|
856
|
-
return meths if skip.include?(fqns)
|
857
|
-
skip.push fqns
|
858
|
-
an = @attr_pins[fqns]
|
859
|
-
unless an.nil?
|
860
|
-
an.each do |pin|
|
861
|
-
meths.push pin_to_suggestion(pin)
|
862
|
-
end
|
863
|
-
end
|
864
|
-
mn = @method_pins[fqns]
|
865
|
-
unless mn.nil?
|
866
|
-
mn.select{|pin| visibility.include?(pin.visibility) and pin.scope == :instance }.each do |pin|
|
867
|
-
meths.push pin_to_suggestion(pin)
|
736
|
+
def inner_get_methods fqns, scope, visibility, deep, skip
|
737
|
+
reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
|
738
|
+
return [] if skip.include?(reqstr)
|
739
|
+
skip.push reqstr
|
740
|
+
result = []
|
741
|
+
if scope == :instance
|
742
|
+
aps = @attr_pins[fqns]
|
743
|
+
result.concat aps unless aps.nil?
|
744
|
+
end
|
745
|
+
mps = @method_pins[fqns]
|
746
|
+
result.concat mps.select{|pin| (pin.scope == scope or fqns == '') and visibility.include?(pin.visibility)} unless mps.nil?
|
747
|
+
if fqns != '' and scope == :class and !result.map(&:path).include?("#{fqns}.new")
|
748
|
+
# Create a [Class].new method pin from [Class]#initialize
|
749
|
+
init = inner_get_methods(fqns, :instance, [:private], deep, skip - [fqns]).select{|pin| pin.name == 'initialize'}.first
|
750
|
+
unless init.nil?
|
751
|
+
result.unshift Solargraph::Pin::Directed::Method.new(init.source, init.node, init.namespace, :class, :public, init.docstring, 'new', init.namespace)
|
868
752
|
end
|
869
753
|
end
|
870
|
-
if
|
754
|
+
if deep
|
871
755
|
sc = @superclasses[fqns]
|
872
756
|
unless sc.nil?
|
873
757
|
sc_visi = [:public]
|
874
|
-
sc_visi.push :protected if
|
875
|
-
|
876
|
-
|
877
|
-
meths.concat yard_map.get_instance_methods(nfqns, '', visibility: sc_visi)
|
758
|
+
sc_visi.push :protected if visibility.include?(:protected)
|
759
|
+
sc_fqns = find_fully_qualified_namespace(sc, fqns)
|
760
|
+
result.concat inner_get_methods(sc_fqns, scope, sc_visi, true, skip)
|
878
761
|
end
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
end
|
887
|
-
meths.uniq
|
888
|
-
end
|
889
|
-
|
890
|
-
# Get a fully qualified namespace for the given signature.
|
891
|
-
# The signature should be in the form of a method chain, e.g.,
|
892
|
-
# method1.method2
|
893
|
-
#
|
894
|
-
# @return [String] The fully qualified namespace for the signature's type
|
895
|
-
# or nil if a type could not be determined
|
896
|
-
def inner_infer_signature_type signature, namespace, scope: :instance, top: true, call_node: nil
|
897
|
-
return nil if signature.nil?
|
898
|
-
signature.gsub!(/\.$/, '')
|
899
|
-
if signature.empty?
|
900
|
-
if scope == :class
|
901
|
-
type = get_namespace_type(namespace)
|
902
|
-
if type == :class
|
903
|
-
return "Class<#{namespace}>"
|
904
|
-
else
|
905
|
-
return "Module<#{namespace}>"
|
762
|
+
if scope == :instance
|
763
|
+
im = @namespace_includes[fqns]
|
764
|
+
unless im.nil?
|
765
|
+
im.each do |i|
|
766
|
+
ifqns = find_fully_qualified_namespace(i, fqns)
|
767
|
+
result.concat inner_get_methods(ifqns, scope, visibility, deep, skip)
|
768
|
+
end
|
906
769
|
end
|
907
|
-
|
908
|
-
|
909
|
-
parts = signature.split('.')
|
910
|
-
type = namespace || ''
|
911
|
-
while (parts.length > 0)
|
912
|
-
part = parts.shift
|
913
|
-
if top == true and part == 'self'
|
914
|
-
top = false
|
915
|
-
next
|
916
|
-
end
|
917
|
-
cls_match = type.match(/^Class<([A-Za-z0-9_:]*?)>$/)
|
918
|
-
if cls_match
|
919
|
-
type = cls_match[1]
|
920
|
-
scope = :class
|
921
|
-
end
|
922
|
-
if scope == :class and part == 'new'
|
923
|
-
scope = :instance
|
770
|
+
result.concat yard_map.get_instance_methods(fqns, visibility: visibility)
|
771
|
+
result.concat inner_get_methods('Object', :instance, [:public], deep, skip) unless fqns == 'Object'
|
924
772
|
else
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
tmp = get_instance_methods(namespace, visibility: visibility)
|
931
|
-
else
|
932
|
-
tmp = get_methods(namespace, visibility: visibility)
|
933
|
-
end
|
934
|
-
tmp.concat get_instance_methods('Kernel', visibility: [:public]) if top
|
935
|
-
matches = tmp.select{|s| s.label == part}
|
936
|
-
return nil if matches.empty?
|
937
|
-
matches.each do |m|
|
938
|
-
type = get_return_type_from_macro(namespace, signature, call_node, scope, visibility)
|
939
|
-
if type.nil?
|
940
|
-
if METHODS_RETURNING_SELF.include?(m.path)
|
941
|
-
type = curtype
|
942
|
-
elsif METHODS_RETURNING_SUBTYPES.include?(m.path)
|
943
|
-
subtypes = get_subtypes(namespace)
|
944
|
-
type = subtypes[0]
|
945
|
-
else
|
946
|
-
type = m.return_type
|
947
|
-
end
|
773
|
+
em = @namespace_extends[fqns]
|
774
|
+
unless em.nil?
|
775
|
+
em.each do |e|
|
776
|
+
efqns = find_fully_qualified_namespace(e, fqns)
|
777
|
+
result.concat inner_get_methods(efqns, :instance, visibility, deep, skip)
|
948
778
|
end
|
949
|
-
break unless type.nil?
|
950
779
|
end
|
951
|
-
|
780
|
+
result.concat yard_map.get_methods(fqns, '', visibility: visibility)
|
781
|
+
type = get_namespace_type(fqns)
|
782
|
+
if type == :class
|
783
|
+
result.concat inner_get_methods('Class', :instance, [:public], deep, skip)
|
784
|
+
else
|
785
|
+
result.concat inner_get_methods('Module', :instance, [:public], deep, skip)
|
786
|
+
end
|
952
787
|
end
|
953
|
-
top = false
|
954
|
-
end
|
955
|
-
if scope == :class and !type.nil?
|
956
|
-
type = "Class<#{type}>"
|
957
788
|
end
|
958
|
-
|
789
|
+
result
|
959
790
|
end
|
960
791
|
|
961
792
|
def inner_get_constants fqns, visibility, skip
|
@@ -976,41 +807,33 @@ module Solargraph
|
|
976
807
|
result
|
977
808
|
end
|
978
809
|
|
979
|
-
#
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
#
|
810
|
+
# Extract a namespace from a type.
|
811
|
+
#
|
812
|
+
# @example
|
813
|
+
# extract_namespace('String') => 'String'
|
814
|
+
# extract_namespace('Class<String>') => 'String'
|
815
|
+
#
|
985
816
|
# @return [String]
|
986
|
-
def
|
987
|
-
|
988
|
-
if result == 'Class' and namespace.include?('<')
|
989
|
-
subtype = namespace.match(/<([a-z0-9:_]*)/i)[1]
|
990
|
-
result = "#{subtype}#class"
|
991
|
-
elsif result == 'Module' and namespace.include?('<')
|
992
|
-
subtype = namespace.match(/<([a-z0-9:_]*)/i)[1]
|
993
|
-
result = "#{subtype}#module"
|
994
|
-
end
|
995
|
-
result
|
817
|
+
def extract_namespace type
|
818
|
+
extract_namespace_and_scope(type)[0]
|
996
819
|
end
|
997
820
|
|
998
|
-
#
|
999
|
-
#
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
821
|
+
# Extract a namespace and a scope (:instance or :class) from a type.
|
822
|
+
#
|
823
|
+
# @example
|
824
|
+
# extract_namespace('String') #=> ['String', :instance]
|
825
|
+
# extract_namespace('Class<String>') #=> ['String', :class]
|
826
|
+
# extract_namespace('Module<Enumerable') #=> ['Enumberable', :class]
|
827
|
+
#
|
828
|
+
# @return [Array] The namespace (String) and scope (Symbol).
|
829
|
+
def extract_namespace_and_scope type
|
830
|
+
scope = :instance
|
831
|
+
result = type.to_s.gsub(/<.*$/, '')
|
832
|
+
if (result == 'Class' or result == 'Module') and type.include?('<')
|
833
|
+
result = type.match(/<([a-z0-9:_]*)/i)[1]
|
834
|
+
scope = :class
|
1012
835
|
end
|
1013
|
-
|
836
|
+
[result, scope]
|
1014
837
|
end
|
1015
838
|
|
1016
839
|
def require_extensions
|
@@ -1020,6 +843,7 @@ module Solargraph
|
|
1020
843
|
end
|
1021
844
|
end
|
1022
845
|
|
846
|
+
# @return [Array<Solargraph::Pin::Base>]
|
1023
847
|
def suggest_unique_variables pins
|
1024
848
|
result = []
|
1025
849
|
nil_pins = []
|
@@ -1029,20 +853,20 @@ module Solargraph
|
|
1029
853
|
nil_pins.push pin
|
1030
854
|
else
|
1031
855
|
unless val_names.include?(pin.name)
|
1032
|
-
result.push
|
856
|
+
result.push pin
|
1033
857
|
val_names.push pin.name
|
1034
858
|
end
|
1035
859
|
end
|
1036
860
|
end
|
1037
861
|
nil_pins.reject{|p| val_names.include?(p.name)}.each do |pin|
|
1038
|
-
result.push
|
862
|
+
result.push pin
|
1039
863
|
end
|
1040
864
|
result
|
1041
865
|
end
|
1042
866
|
|
1043
867
|
def source_file_mtime(filename)
|
1044
868
|
# @todo This is naively inefficient.
|
1045
|
-
sources.each do |s|
|
869
|
+
@sources.each do |s|
|
1046
870
|
return s.mtime if s.filename == filename
|
1047
871
|
end
|
1048
872
|
nil
|
@@ -1060,25 +884,6 @@ module Solargraph
|
|
1060
884
|
set.select{|p| p.path == fqns}
|
1061
885
|
end
|
1062
886
|
|
1063
|
-
def get_namespace_nodes(fqns)
|
1064
|
-
return file_nodes if fqns == '' or fqns.nil?
|
1065
|
-
refresh
|
1066
|
-
namespace_map[fqns] || []
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
# @return [Array<String>]
|
1070
|
-
def get_include_strings_from *nodes
|
1071
|
-
arr = []
|
1072
|
-
nodes.each { |node|
|
1073
|
-
next unless node.kind_of?(AST::Node)
|
1074
|
-
arr.push unpack_name(node.children[2]) if (node.type == :send and node.children[1] == :include)
|
1075
|
-
node.children.each { |n|
|
1076
|
-
arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module and n.type != :sclass
|
1077
|
-
}
|
1078
|
-
}
|
1079
|
-
arr
|
1080
|
-
end
|
1081
|
-
|
1082
887
|
# @todo DRY this method. It's duplicated in CodeMap
|
1083
888
|
def get_subtypes type
|
1084
889
|
return nil if type.nil?
|
@@ -1092,15 +897,28 @@ module Solargraph
|
|
1092
897
|
@path_macros ||= {}
|
1093
898
|
end
|
1094
899
|
|
900
|
+
def get_call_arguments node
|
901
|
+
return get_call_arguments(node.children[1]) if [:ivasgn, :cvasgn, :lvasgn].include?(node.type)
|
902
|
+
return [] unless node.type == :send
|
903
|
+
result = []
|
904
|
+
node.children[2..-1].each do |c|
|
905
|
+
result.push unpack_name(c)
|
906
|
+
end
|
907
|
+
result
|
908
|
+
end
|
909
|
+
|
910
|
+
# @todo This method shouldn't need to calculate the path. In fact, it should work directly off a pin.
|
1095
911
|
def get_return_type_from_macro namespace, signature, call_node, scope, visibility
|
1096
912
|
return nil if signature.empty? or signature.include?('.') or call_node.nil?
|
1097
913
|
path = "#{namespace}#{scope == :class ? '.' : '#'}#{signature}"
|
1098
914
|
macmeth = get_path_suggestions(path).first
|
1099
915
|
type = nil
|
1100
916
|
unless macmeth.nil?
|
917
|
+
macmeths = Suggestion.pull(macmeth)
|
1101
918
|
macro = path_macros[macmeth.path]
|
1102
919
|
macro = macro.first unless macro.nil?
|
1103
|
-
|
920
|
+
# @todo Smelly respond_to? call
|
921
|
+
if macro.nil? and macmeth.respond_to?(:code_object) and !macmeth.code_object.nil? and !macmeth.code_object.base_docstring.nil? and macmeth.code_object.base_docstring.all.include?('@!macro')
|
1104
922
|
all = YARD::Docstring.parser.parse(macmeth.code_object.base_docstring.all).directives
|
1105
923
|
macro = all.select{|m| m.tag.tag_name == 'macro'}.first
|
1106
924
|
end
|
@@ -1115,5 +933,115 @@ module Solargraph
|
|
1115
933
|
end
|
1116
934
|
type
|
1117
935
|
end
|
936
|
+
|
937
|
+
def inner_infer_signature_type signature, namespace, scope, call_node, top
|
938
|
+
namespace ||= ''
|
939
|
+
if cache.has_signature_type?(signature, namespace, scope)
|
940
|
+
return cache.get_signature_type(signature, namespace, scope)
|
941
|
+
end
|
942
|
+
return nil if signature.nil?
|
943
|
+
return namespace if signature.empty? and scope == :instance
|
944
|
+
return nil if signature.empty? # @todo This might need to return Class<namespace>
|
945
|
+
if !signature.include?('.')
|
946
|
+
fqns = find_fully_qualified_namespace(signature, namespace)
|
947
|
+
unless fqns.nil? or fqns.empty?
|
948
|
+
type = (get_namespace_type(fqns) == :class ? 'Class' : 'Module')
|
949
|
+
return "#{type}<#{fqns}>"
|
950
|
+
end
|
951
|
+
end
|
952
|
+
result = nil
|
953
|
+
parts = signature.split('.', 2)
|
954
|
+
type = find_fully_qualified_namespace(parts[0], namespace)
|
955
|
+
if type.nil?
|
956
|
+
# It's a variable or method call
|
957
|
+
if top and parts[0] == 'self'
|
958
|
+
if parts[1].nil?
|
959
|
+
result = namespace
|
960
|
+
else
|
961
|
+
return inner_infer_signature_type(parts[1], namespace, scope, call_node, false)
|
962
|
+
end
|
963
|
+
elsif parts[0] == 'new' and scope == :class
|
964
|
+
scope = :instance
|
965
|
+
if parts[1].nil?
|
966
|
+
result = namespace
|
967
|
+
else
|
968
|
+
result = inner_infer_signature_type(parts[1], namespace, :instance, call_node, false)
|
969
|
+
end
|
970
|
+
else
|
971
|
+
visibility = [:public]
|
972
|
+
visibility.concat [:private, :protected] if top
|
973
|
+
if scope == :instance || namespace == ''
|
974
|
+
tmp = get_methods(extract_namespace(namespace), visibility: visibility)
|
975
|
+
else
|
976
|
+
tmp = get_methods(namespace, visibility: visibility, scope: :class)
|
977
|
+
# tmp = get_type_methods(namespace, (top ? namespace : ''))
|
978
|
+
end
|
979
|
+
tmp.concat get_methods('Kernel', visibility: [:public]) if top
|
980
|
+
matches = tmp.select{|s| s.name == parts[0]}
|
981
|
+
return nil if matches.empty?
|
982
|
+
matches.each do |m|
|
983
|
+
type = get_return_type_from_macro(namespace, signature, call_node, scope, visibility)
|
984
|
+
if type.nil?
|
985
|
+
if METHODS_RETURNING_SELF.include?(m.path)
|
986
|
+
type = curtype
|
987
|
+
elsif METHODS_RETURNING_SUBTYPES.include?(m.path)
|
988
|
+
subtypes = get_subtypes(namespace)
|
989
|
+
type = subtypes[0]
|
990
|
+
elsif !m.return_type.nil?
|
991
|
+
if m.return_type == 'self'
|
992
|
+
type = combine_type(namespace, scope)
|
993
|
+
else
|
994
|
+
type = m.return_type
|
995
|
+
end
|
996
|
+
end
|
997
|
+
end
|
998
|
+
break unless type.nil?
|
999
|
+
end
|
1000
|
+
unless type.nil?
|
1001
|
+
scope = :instance
|
1002
|
+
if parts[1].nil?
|
1003
|
+
result = type
|
1004
|
+
else
|
1005
|
+
subns, subsc = extract_namespace_and_scope(type)
|
1006
|
+
result = inner_infer_signature_type(parts[1], subns, subsc, call_node, false)
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
else
|
1011
|
+
return inner_infer_signature_type(parts[1], type, :class, call_node, false)
|
1012
|
+
end
|
1013
|
+
# @todo Assuming `self` only works at the top level
|
1014
|
+
# result = type if result == 'self'
|
1015
|
+
unless result.nil?
|
1016
|
+
if scope == :class
|
1017
|
+
nstype = get_namespace_type(result)
|
1018
|
+
result = "#{nstype == :class ? 'Class<' : 'Module<'}#{result}>"
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
cache.set_signature_type signature, namespace, scope, result
|
1022
|
+
result
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
# @todo call_node might be superfluous here. We're already past looking for local variables.
|
1026
|
+
def inner_infer_signature_pins signature, namespace, scope, call_node, top
|
1027
|
+
base, rest = signature.split('.', 2)
|
1028
|
+
type = nil
|
1029
|
+
if rest.nil?
|
1030
|
+
visibility = [:public]
|
1031
|
+
visibility.push :private, :protected if top
|
1032
|
+
methods = []
|
1033
|
+
methods.concat get_methods(namespace, visibility: visibility, scope: scope).select{|pin| pin.name == base}
|
1034
|
+
methods.concat get_methods('Kernel', scope: :instance).select{|pin| pin.name == base} if top
|
1035
|
+
return methods
|
1036
|
+
else
|
1037
|
+
type = inner_infer_signature_type base, namespace, scope, call_node, top
|
1038
|
+
nxt_ns, nxt_scope = extract_namespace_and_scope(type)
|
1039
|
+
return inner_infer_signature_pins rest, nxt_ns, nxt_scope, call_node, false
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
def current_workspace_sources
|
1044
|
+
@sources - [@virtual_source]
|
1045
|
+
end
|
1118
1046
|
end
|
1119
1047
|
end
|