solargraph 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +18 -16
  3. data/lib/solargraph/api_map.rb +100 -161
  4. data/lib/solargraph/api_map/source_to_yard.rb +9 -9
  5. data/lib/solargraph/api_map/store.rb +50 -13
  6. data/lib/solargraph/basic_type.rb +33 -0
  7. data/lib/solargraph/basic_type_methods.rb +111 -0
  8. data/lib/solargraph/complex_type.rb +51 -89
  9. data/lib/solargraph/core_fills.rb +12 -8
  10. data/lib/solargraph/diagnostics/type_not_defined.rb +2 -2
  11. data/lib/solargraph/language_server.rb +3 -0
  12. data/lib/solargraph/language_server/completion_item_kinds.rb +2 -0
  13. data/lib/solargraph/language_server/error_codes.rb +2 -0
  14. data/lib/solargraph/language_server/host.rb +53 -6
  15. data/lib/solargraph/language_server/message.rb +13 -0
  16. data/lib/solargraph/language_server/message/text_document/definition.rb +4 -6
  17. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -1
  18. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -1
  19. data/lib/solargraph/language_server/message_types.rb +2 -0
  20. data/lib/solargraph/language_server/request.rb +4 -0
  21. data/lib/solargraph/language_server/symbol_kinds.rb +28 -26
  22. data/lib/solargraph/language_server/transport.rb +3 -0
  23. data/lib/solargraph/language_server/uri_helpers.rb +2 -0
  24. data/lib/solargraph/library.rb +12 -7
  25. data/lib/solargraph/pin.rb +1 -1
  26. data/lib/solargraph/pin/attribute.rb +5 -5
  27. data/lib/solargraph/pin/base.rb +51 -16
  28. data/lib/solargraph/pin/base_variable.rb +25 -7
  29. data/lib/solargraph/pin/block.rb +18 -1
  30. data/lib/solargraph/pin/block_parameter.rb +42 -5
  31. data/lib/solargraph/pin/conversions.rb +4 -2
  32. data/lib/solargraph/pin/method.rb +6 -6
  33. data/lib/solargraph/pin/method_parameter.rb +6 -6
  34. data/lib/solargraph/pin/namespace.rb +7 -2
  35. data/lib/solargraph/pin/proxy_type.rb +39 -0
  36. data/lib/solargraph/pin/symbol.rb +20 -12
  37. data/lib/solargraph/pin/yard_pin/method.rb +2 -2
  38. data/lib/solargraph/source.rb +89 -38
  39. data/lib/solargraph/source/call_chainer.rb +273 -0
  40. data/lib/solargraph/source/chain.rb +104 -0
  41. data/lib/solargraph/source/chain/call.rb +72 -0
  42. data/lib/solargraph/source/chain/class_variable.rb +11 -0
  43. data/lib/solargraph/source/chain/constant.rb +17 -0
  44. data/lib/solargraph/source/chain/definition.rb +16 -0
  45. data/lib/solargraph/source/chain/global_variable.rb +11 -0
  46. data/lib/solargraph/source/chain/head.rb +20 -0
  47. data/lib/solargraph/source/chain/instance_variable.rb +11 -0
  48. data/lib/solargraph/source/chain/link.rb +33 -0
  49. data/lib/solargraph/source/chain/literal.rb +21 -0
  50. data/lib/solargraph/source/chain/variable.rb +11 -0
  51. data/lib/solargraph/source/change.rb +3 -1
  52. data/lib/solargraph/{api_map → source}/completion.rb +3 -1
  53. data/lib/solargraph/source/encoding_fixes.rb +21 -0
  54. data/lib/solargraph/source/fragment.rb +139 -284
  55. data/lib/solargraph/source/mapper.rb +27 -16
  56. data/lib/solargraph/source/node_chainer.rb +94 -0
  57. data/lib/solargraph/source/node_methods.rb +2 -2
  58. data/lib/solargraph/source/position.rb +4 -0
  59. data/lib/solargraph/source/range.rb +10 -2
  60. data/lib/solargraph/version.rb +1 -1
  61. data/lib/solargraph/yard_map.rb +13 -2
  62. metadata +20 -6
  63. data/lib/solargraph/api_map/probe.rb +0 -251
  64. data/lib/solargraph/api_map/type_methods.rb +0 -40
  65. data/lib/solargraph/pin/proxy_method.rb +0 -30
@@ -20,11 +20,15 @@ module Solargraph
20
20
  @node = node
21
21
  @node_stack = []
22
22
  @directives = {}
23
+ @comment_ranges = comments.map do |c|
24
+ Source::Range.from_to(c.loc.expression.line, c.loc.expression.column, c.loc.expression.last_line, c.loc.expression.last_column)
25
+ end
23
26
  @node_comments = associate_comments(node, comments)
24
27
  @pins = []
25
28
  @requires = []
26
29
  @symbols = []
27
30
  @locals = []
31
+ @strings = []
28
32
 
29
33
  @used_comment_locs = []
30
34
 
@@ -37,7 +41,8 @@ module Solargraph
37
41
  @node_comments.reject{|k, v| @used_comment_locs.include?(k)}.each do |k, v|
38
42
  @pins.first.comments.concat v
39
43
  end
40
- [@pins, @locals, @requires, @symbols]
44
+
45
+ [@pins, @locals, @requires, @symbols, @strings, @comment_ranges]
41
46
  end
42
47
 
43
48
  class << self
@@ -70,7 +75,13 @@ module Solargraph
70
75
  @pins ||= []
71
76
  end
72
77
 
78
+ # @param node [Parser::AST::Node]
73
79
  def process node, tree = [], visibility = :public, scope = :instance, fqn = '', stack = []
80
+ return unless node.is_a?(AST::Node)
81
+ if node.type == :str
82
+ @strings.push Source::Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
83
+ return
84
+ end
74
85
  stack.push node
75
86
  if node.kind_of?(AST::Node)
76
87
  @node_stack.unshift node
@@ -98,17 +109,17 @@ module Solargraph
98
109
  ora = find_parent(stack, :or_asgn)
99
110
  unless ora.nil?
100
111
  u = c.updated(:ivasgn, c.children + ora.children[1..-1], nil)
101
- pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), resolve_node_signature(u.children[1]), infer_literal_node_type(u.children[1]), context)
112
+ pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), context)
102
113
  if visibility == :module_function and context.kind == Pin::METHOD
103
114
  other = pins.select{|pin| pin.path == "#{context.namespace}.#{context.name}"}.first
104
- pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), resolve_node_signature(u.children[1]), infer_literal_node_type(u.children[1]), other) unless other.nil?
115
+ pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), other) unless other.nil?
105
116
  end
106
117
  end
107
118
  else
108
- pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), resolve_node_signature(c.children[1]), infer_literal_node_type(c.children[1]), context)
119
+ pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context)
109
120
  if visibility == :module_function and context.kind == Pin::METHOD
110
121
  other = pins.select{|pin| pin.path == "#{context.namespace}.#{context.name}"}.first
111
- pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), resolve_node_signature(c.children[1]), infer_literal_node_type(c.children[1]), other)
122
+ pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), other)
112
123
  end
113
124
  end
114
125
  elsif c.type == :cvasgn
@@ -118,10 +129,10 @@ module Solargraph
118
129
  ora = find_parent(stack, :or_asgn)
119
130
  unless ora.nil?
120
131
  u = c.updated(:cvasgn, c.children + ora.children[1..-1], nil)
121
- pins.push Solargraph::Pin::ClassVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), resolve_node_signature(u.children[1]), infer_literal_node_type(u.children[1]), context)
132
+ pins.push Solargraph::Pin::ClassVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), context)
122
133
  end
123
134
  else
124
- pins.push Solargraph::Pin::ClassVariable.new(get_node_location(c), fqn || '', c.children[0].to_s, comments_for(c), resolve_node_signature(c.children[1]), infer_literal_node_type(c.children[1]), context)
135
+ pins.push Solargraph::Pin::ClassVariable.new(get_node_location(c), fqn || '', c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context)
125
136
  end
126
137
  elsif c.type == :lvasgn
127
138
  here = get_node_start_position(c)
@@ -132,25 +143,25 @@ module Solargraph
132
143
  ora = find_parent(stack, :or_asgn)
133
144
  unless ora.nil?
134
145
  u = c.updated(:lvasgn, c.children + ora.children[1..-1], nil)
135
- @locals.push Solargraph::Pin::LocalVariable.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(ora), resolve_node_signature(c.children[1]), infer_literal_node_type(c.children[1]), context, block, presence)
146
+ @locals.push Solargraph::Pin::LocalVariable.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(ora), c.children[1], infer_literal_node_type(c.children[1]), context, block, presence)
136
147
  end
137
148
  else
138
- @locals.push Solargraph::Pin::LocalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), resolve_node_signature(c.children[1]), infer_literal_node_type(c.children[1]), context, block, presence)
149
+ @locals.push Solargraph::Pin::LocalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context, block, presence)
139
150
  end
140
151
  elsif c.type == :gvasgn
141
- pins.push Solargraph::Pin::GlobalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), resolve_node_signature(c.children[1]), infer_literal_node_type(c.children[1]), @pins.first)
152
+ pins.push Solargraph::Pin::GlobalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), @pins.first)
142
153
  elsif c.type == :sym
143
154
  @symbols.push Solargraph::Pin::Symbol.new(get_node_location(c), ":#{c.children[0]}")
144
155
  elsif c.type == :casgn
145
156
  here = get_node_start_position(c)
146
157
  block = get_block_pin(here)
147
- pins.push Solargraph::Pin::Constant.new(get_node_location(c), fqn, c.children[1].to_s, comments_for(c), resolve_node_signature(c.children[2]), infer_literal_node_type(c.children[2]), block, :public)
158
+ pins.push Solargraph::Pin::Constant.new(get_node_location(c), fqn, c.children[1].to_s, comments_for(c), c.children[2], infer_literal_node_type(c.children[2]), block, :public)
148
159
  elsif c.type == :def
149
160
  methpin = Solargraph::Pin::Method.new(get_node_location(c), fqn || '', c.children[(c.type == :def ? 0 : 1)].to_s, comments_for(c), scope, visibility, get_method_args(c))
150
161
  if methpin.name == 'initialize' and methpin.scope == :instance
151
162
  pins.push Solargraph::Pin::Method.new(methpin.location, methpin.namespace, 'new', methpin.comments, :class, :public, methpin.parameters)
152
163
  # @todo Smelly instance variable access.
153
- pins.last.instance_variable_set(:@return_complex_types, ComplexType.parse(methpin.namespace))
164
+ pins.last.instance_variable_set(:@return_complex_type, ComplexType.parse(methpin.namespace))
154
165
  pins.push Solargraph::Pin::Method.new(methpin.location, methpin.namespace, methpin.name, methpin.comments, methpin.scope, :private, methpin.parameters)
155
166
  elsif visibility == :module_function
156
167
  pins.push Solargraph::Pin::Method.new(methpin.location, methpin.namespace, methpin.name, methpin.comments, :class, :public, methpin.parameters)
@@ -290,7 +301,7 @@ module Solargraph
290
301
  end
291
302
  end
292
303
  elsif c.type == :block
293
- @pins.push Solargraph::Pin::Block.new(get_node_location(c), fqn || '', '', comments_for(c), resolve_node_signature(c.children[0]))
304
+ @pins.push Solargraph::Pin::Block.new(get_node_location(c), fqn || '', '', comments_for(c), c.children[0], scope)
294
305
  end
295
306
  process c, tree, visibility, scope, fqn, stack
296
307
  end
@@ -333,8 +344,8 @@ module Solargraph
333
344
  st = Position.new(0, 0)
334
345
  en = Position.from_offset(@code, @code.length)
335
346
  else
336
- st = Position.new(node.loc.line - 1, node.loc.column)
337
- en = Position.new(node.loc.last_line - 1, node.loc.last_column)
347
+ st = Position.new(node.loc.line, node.loc.column)
348
+ en = Position.new(node.loc.last_line, node.loc.last_column)
338
349
  end
339
350
  range = Range.new(st, en)
340
351
  Location.new(filename, range)
@@ -371,7 +382,7 @@ module Solargraph
371
382
  # @param node [Parser::AST::Node]
372
383
  # @return [Solargraph::Pin::Namespace]
373
384
  def namespace_for(node)
374
- position = Source::Position.new(node.loc.line - 1, node.loc.column)
385
+ position = Source::Position.new(node.loc.line, node.loc.column)
375
386
  @pins.select{|pin| pin.kind == Pin::NAMESPACE and pin.location.range.contain?(position)}.last
376
387
  end
377
388
 
@@ -0,0 +1,94 @@
1
+ module Solargraph
2
+ class Source
3
+ class NodeChainer
4
+ include NodeMethods
5
+
6
+ def initialize filename, node
7
+ @filename = filename
8
+ @node = node
9
+ # @source = source
10
+ # @line = line
11
+ # @column = column
12
+ end
13
+
14
+ # @return [Source::Chain]
15
+ def chain
16
+ links = generate_links(@node)
17
+ Chain.new(@filename, links)
18
+ end
19
+
20
+ class << self
21
+ # @param source [Source]
22
+ # @param line [Integer]
23
+ # @param column [Integer]
24
+ # @return [Source::Chain]
25
+ def chain filename, node
26
+ NodeChainer.new(filename, node).chain
27
+ end
28
+
29
+ # @param code [String]
30
+ # @return [Chain]
31
+ def load_string(filename, code)
32
+ node = Source.parse_node(code.sub(/\.$/, ''), filename)
33
+ chain = Chain.new(filename, node)
34
+ chain.links.push(Chain::Link.new) if code.end_with?('.')
35
+ chain
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @param n [Parser::AST::Node]
42
+ # @return [Array<Chain::Link>]
43
+ def generate_links n
44
+ return [] if n.nil?
45
+ return generate_links(n.children[0]) if n.type == :begin
46
+ # @todo This might not be right. It's weird either way.
47
+ # return generate_links(n.children[2] || n.children[0]) if n.type == :block
48
+ result = []
49
+ if n.type == :block
50
+ # result.concat generate_links(n.children[2])
51
+ result.concat generate_links(n.children[0])
52
+ elsif n.type == :send
53
+ if n.children[0].is_a?(Parser::AST::Node)
54
+ result.concat generate_links(n.children[0])
55
+ args = []
56
+ n.children[2..-1].each do |c|
57
+ # @todo Handle link parameters
58
+ # args.push Chain.new(source, c.loc.last_line - 1, c.loc.column)
59
+ end
60
+ result.push Chain::Call.new(n.children[1].to_s, args)
61
+ elsif n.children[0].nil?
62
+ args = []
63
+ n.children[2..-1].each do |c|
64
+ # @todo Handle link parameters
65
+ # args.push Chain.new(source, c.loc.last_line - 1, c.loc.column)
66
+ end
67
+ result.push Chain::Call.new(n.children[1].to_s, args)
68
+ else
69
+ raise "No idea what to do with #{n}"
70
+ end
71
+ elsif n.type == :self
72
+ result.push Chain::Call.new('self')
73
+ elsif n.type == :const
74
+ result.push Chain::Constant.new(unpack_name(n))
75
+ elsif [:lvar, :lvasgn].include?(n.type)
76
+ result.push Chain::Call.new(n.children[0].to_s)
77
+ elsif [:ivar, :ivasgn].include?(n.type)
78
+ result.push Chain::InstanceVariable.new(n.children[0].to_s)
79
+ elsif [:cvar, :cvasgn].include?(n.type)
80
+ result.push Chain::ClassVariable.new(n.children[0].to_s)
81
+ elsif [:gvar, :gvasgn].include?(n.type)
82
+ result.push Chain::GlobalVariable.new(n.children[0].to_s)
83
+ elsif [:class, :module, :def, :defs].include?(n.type)
84
+ location = Solargraph::Source::Location.new(@filename, Source::Range.from_to(n.loc.expression.line - 1, n.loc.expression.column, n.loc.expression.last_line - 1, n.loc.expression.last_column))
85
+ result.push Chain::Definition.new(location)
86
+ else
87
+ lit = infer_literal_node_type(n)
88
+ result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
89
+ end
90
+ result
91
+ end
92
+ end
93
+ end
94
+ end
@@ -79,11 +79,11 @@ module Solargraph
79
79
  end
80
80
 
81
81
  def get_node_start_position(node)
82
- Position.new(node.loc.line - 1, node.loc.column)
82
+ Position.new(node.loc.line, node.loc.column)
83
83
  end
84
84
 
85
85
  def get_node_end_position(node)
86
- Position.new(node.loc.last_line - 1, node.loc.last_column)
86
+ Position.new(node.loc.last_line, node.loc.last_column)
87
87
  end
88
88
 
89
89
  def drill_signature node, signature
@@ -13,6 +13,10 @@ module Solargraph
13
13
  @character = character
14
14
  end
15
15
 
16
+ def column
17
+ character
18
+ end
19
+
16
20
  # Get a hash of the position. This representation is suitable for use in
17
21
  # the language server protocol.
18
22
  #
@@ -27,15 +27,23 @@ module Solargraph
27
27
 
28
28
  # True if the specified position is inside the range.
29
29
  #
30
+ # @param position [Solargraph::Source::Position]
30
31
  # @return [Boolean]
31
32
  def contain? position
32
- return false if position.line < start.line
33
+ return false if position.line < start.line or position.line > ending.line
33
34
  return false if position.line == start.line and position.character < start.character
34
- return false if position.line > ending.line
35
35
  return false if position.line == ending.line and position.character > ending.character
36
36
  true
37
37
  end
38
38
 
39
+ # True if the range contains the specified position and the position does not precede it.
40
+ #
41
+ # @param position [Source::Position]
42
+ # @return [Boolean]
43
+ def include? position
44
+ contain?(position) and !(position.line == start.line and position.character == start.character)
45
+ end
46
+
39
47
  # Create a range from a pair of lines and characters.
40
48
  #
41
49
  # @param l1 [Integer] Starting line
@@ -1,3 +1,3 @@
1
1
  module Solargraph
2
- VERSION = '0.25.1'
2
+ VERSION = '0.26.0'
3
3
  end
@@ -26,6 +26,8 @@ module Solargraph
26
26
  # @return [Array<String>]
27
27
  attr_reader :required
28
28
 
29
+ # @param required [Array<String>]
30
+ # @param workspace [Solargraph::Workspace, nil]
29
31
  def initialize(required: [], workspace: nil)
30
32
  @workspace = workspace
31
33
  # HACK: YardMap needs its own copy of this array
@@ -69,7 +71,7 @@ module Solargraph
69
71
  end
70
72
  end
71
73
 
72
- # @param paths [Array<String>]
74
+ # @param new_requires [Array<String>]
73
75
  # @return [Boolean]
74
76
  def change new_requires
75
77
  if new_requires.uniq.sort == required.uniq.sort
@@ -82,6 +84,7 @@ module Solargraph
82
84
  end
83
85
  end
84
86
 
87
+ # @return [Array<Solargraph::Pin::Base>]
85
88
  def core_pins
86
89
  @@core_pins ||= begin
87
90
  result = []
@@ -100,6 +103,8 @@ module Solargraph
100
103
  @cache ||= YardMap::Cache.new
101
104
  end
102
105
 
106
+ # @param ns [YARD::CodeObjects::Namespace]
107
+ # @return [Array<Solargraph::Pin::Base>]
103
108
  def recurse_namespace_object ns
104
109
  result = []
105
110
  ns.children.each do |c|
@@ -109,6 +114,8 @@ module Solargraph
109
114
  result
110
115
  end
111
116
 
117
+ # @param code_object [YARD::CodeObjects::Base]
118
+ # @return [Solargraph::Pin::Base]
112
119
  def generate_pin code_object
113
120
  location = object_location(code_object)
114
121
  if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
@@ -122,6 +129,7 @@ module Solargraph
122
129
  end
123
130
  end
124
131
 
132
+ # @return [void]
125
133
  def process_requires
126
134
  pins.clear
127
135
  unresolved_requires.clear
@@ -177,6 +185,8 @@ module Solargraph
177
185
  pins.concat core_pins
178
186
  end
179
187
 
188
+ # @param required_namespaces [Array<YARD::CodeObjects::Namespace>]
189
+ # @return [Array<Solargraph::Pin::Base>]
180
190
  def process_stdlib required_namespaces
181
191
  pins = []
182
192
  unless required_namespaces.empty?
@@ -199,6 +209,7 @@ module Solargraph
199
209
  end
200
210
 
201
211
  # @param spec [Gem::Specification]
212
+ # @return [void]
202
213
  def add_gem_dependencies spec
203
214
  (spec.dependencies - spec.development_dependencies).each do |dep|
204
215
  depspec = Gem::Specification.find_by_name(dep.name)
@@ -218,7 +229,7 @@ module Solargraph
218
229
  return nil if obj.file.nil? or obj.line.nil?
219
230
  @gem_paths.values.each do |path|
220
231
  file = File.join(path, obj.file)
221
- return Solargraph::Source::Location.new(file, Solargraph::Source::Range.from_to(obj.line - 1, 0, obj.line - 1, 0)) if File.exist?(file)
232
+ return Solargraph::Source::Location.new(file, Solargraph::Source::Range.from_to(obj.line, 0, obj.line, 0)) if File.exist?(file)
222
233
  end
223
234
  nil
224
235
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.1
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-20 00:00:00.000000000 Z
11
+ date: 2018-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -236,11 +236,10 @@ files:
236
236
  - lib/solargraph.rb
237
237
  - lib/solargraph/api_map.rb
238
238
  - lib/solargraph/api_map/cache.rb
239
- - lib/solargraph/api_map/completion.rb
240
- - lib/solargraph/api_map/probe.rb
241
239
  - lib/solargraph/api_map/source_to_yard.rb
242
240
  - lib/solargraph/api_map/store.rb
243
- - lib/solargraph/api_map/type_methods.rb
241
+ - lib/solargraph/basic_type.rb
242
+ - lib/solargraph/basic_type_methods.rb
244
243
  - lib/solargraph/complex_type.rb
245
244
  - lib/solargraph/core_fills.rb
246
245
  - lib/solargraph/diagnostics.rb
@@ -324,7 +323,7 @@ files:
324
323
  - lib/solargraph/pin/method_parameter.rb
325
324
  - lib/solargraph/pin/namespace.rb
326
325
  - lib/solargraph/pin/plugin/method.rb
327
- - lib/solargraph/pin/proxy_method.rb
326
+ - lib/solargraph/pin/proxy_type.rb
328
327
  - lib/solargraph/pin/reference.rb
329
328
  - lib/solargraph/pin/symbol.rb
330
329
  - lib/solargraph/pin/yard_pin.rb
@@ -340,11 +339,26 @@ files:
340
339
  - lib/solargraph/server_methods.rb
341
340
  - lib/solargraph/shell.rb
342
341
  - lib/solargraph/source.rb
342
+ - lib/solargraph/source/call_chainer.rb
343
+ - lib/solargraph/source/chain.rb
344
+ - lib/solargraph/source/chain/call.rb
345
+ - lib/solargraph/source/chain/class_variable.rb
346
+ - lib/solargraph/source/chain/constant.rb
347
+ - lib/solargraph/source/chain/definition.rb
348
+ - lib/solargraph/source/chain/global_variable.rb
349
+ - lib/solargraph/source/chain/head.rb
350
+ - lib/solargraph/source/chain/instance_variable.rb
351
+ - lib/solargraph/source/chain/link.rb
352
+ - lib/solargraph/source/chain/literal.rb
353
+ - lib/solargraph/source/chain/variable.rb
343
354
  - lib/solargraph/source/change.rb
355
+ - lib/solargraph/source/completion.rb
356
+ - lib/solargraph/source/encoding_fixes.rb
344
357
  - lib/solargraph/source/flawed_builder.rb
345
358
  - lib/solargraph/source/fragment.rb
346
359
  - lib/solargraph/source/location.rb
347
360
  - lib/solargraph/source/mapper.rb
361
+ - lib/solargraph/source/node_chainer.rb
348
362
  - lib/solargraph/source/node_methods.rb
349
363
  - lib/solargraph/source/position.rb
350
364
  - lib/solargraph/source/range.rb
@@ -1,251 +0,0 @@
1
- module Solargraph
2
- class ApiMap
3
- # A deep analysis provider for ApiMaps.
4
- #
5
- class Probe
6
- include TypeMethods
7
-
8
- # @return [Solargraph::ApiMap]
9
- attr_reader :api_map
10
-
11
- # @param api_map [ApiMap]
12
- def initialize api_map
13
- @api_map = api_map
14
- end
15
-
16
- # Get all matching pins for the signature.
17
- #
18
- # @param signature [String]
19
- # @param context_pin [Pin::Base]
20
- # @param locals [Array<Pin::Base>]
21
- # @return [Array<Pin::Base>]
22
- def infer_signature_pins signature, context_pin, locals
23
- return [] if signature.nil? or signature.empty?
24
- base, rest = signature.split('.', 2)
25
- return infer_word_pins(base, context_pin, locals) if rest.nil?
26
- pins = infer_word_pins(base, context_pin, locals).map do |pin|
27
- next pin unless pin.return_type.nil?
28
- type = resolve_pin_type(pin, locals - [pin])
29
- Pin::ProxyMethod.new(type)
30
- end
31
- return [] if pins.empty?
32
- rest = rest.split('.')
33
- last = rest.pop
34
- rest.each do |meth|
35
- found = nil
36
- pins.each do |pin|
37
- found = infer_method_name_pins(meth, pin)
38
- next if found.empty?
39
- pins = found
40
- break
41
- end
42
- return [] if found.nil?
43
- end
44
- pins.each do |pin|
45
- found = infer_method_name_pins(last, pin)
46
- return found unless found.empty?
47
- end
48
- []
49
- end
50
-
51
- # Get the return type for the signature.
52
- #
53
- # @param signature [String]
54
- # @param context_pin [Pin::Base]
55
- # @param locals [Array<Pin::Base>]
56
- # @return [String]
57
- def infer_signature_type signature, context_pin, locals
58
- pins = infer_signature_pins(signature, context_pin, locals)
59
- pins.each do |pin|
60
- return qualify(pin.return_type, pin.named_context) unless pin.return_type.nil?
61
- type = resolve_pin_type(pin, locals - [pin])
62
- return qualify(type, pin.named_context) unless type.nil?
63
- end
64
- nil
65
- end
66
-
67
- private
68
-
69
- # Word search is ALWAYS internal
70
- def infer_word_pins word, context_pin, locals
71
- return [] if word.empty?
72
- return infer_self(context_pin) if word == 'self'
73
- lvars = locals.select{|pin| pin.name == word}
74
- return resolve_word_types(lvars, locals) unless lvars.empty?
75
- return api_map.get_global_variable_pins.select{|pin| pin.name == word} if word.start_with?('$')
76
- namespace, scope = extract_namespace_and_scope_from_pin(context_pin)
77
- return api_map.get_class_variable_pins(namespace).select{|pin| pin.name == word} if word.start_with?('@@')
78
- return api_map.get_instance_variable_pins(namespace, scope).select{|pin| pin.name == word} if word.start_with?('@')
79
- return api_map.pins.select{|pin| word_matches_context?(word, namespace, scope, pin)} if variable_name?(word)
80
- result = []
81
- cparts = namespace.split('::')
82
- until cparts.empty?
83
- break unless result.empty?
84
- cur = cparts.join('::')
85
- result.concat api_map.get_path_suggestions("#{cur}::#{word}")
86
- cparts.pop
87
- end
88
- result.concat api_map.get_path_suggestions(word) if result.empty?
89
- # result.concat api_map.get_methods(namespace, scope: scope, visibility: [:public, :private, :protected]).select{|pin| pin.name == word} unless word.include?('::')
90
- result.concat api_map.get_method_stack(namespace, word, scope: scope) unless word.include?('::')
91
- result.concat api_map.get_constants('', namespace).select{|pin| pin.name == word} if result.empty?
92
- resolve_word_types(result, locals)
93
- end
94
-
95
- def resolve_word_types(pins, locals)
96
- pins.each do |p|
97
- next unless p.return_type.nil?
98
- type = resolve_pin_type(p, locals)
99
- # @todo Smelly instance variable access
100
- p.instance_variable_set(:@return_complex_types, ComplexType.parse(type)) unless type.nil?
101
- end
102
- pins
103
- end
104
-
105
- def infer_self context_pin
106
- if context_pin.kind == Pin::METHOD
107
- if context_pin.scope == :instance
108
- return [Pin::ProxyMethod.new(context_pin.namespace)]
109
- else
110
- return api_map.get_path_suggestions(context_pin.namespace)
111
- end
112
- else
113
- return api_map.get_path_suggestions(context_pin.path)
114
- end
115
- end
116
-
117
- # Method name search is external by default
118
- # @param method_name [String]
119
- # @param context_pin [Solargraph::Pin::Base]
120
- def infer_method_name_pins method_name, context_pin, internal = false
121
- relname, scope = extract_namespace_and_scope(context_pin.return_type)
122
- namespace = api_map.qualify(relname, context_pin.namespace)
123
- visibility = [:public]
124
- visibility.push :protected, :private if internal
125
- # result = api_map.get_methods(namespace, scope: scope, visibility: visibility).select{|pin| pin.name == method_name}
126
- result = api_map.get_method_stack(namespace, method_name, scope: scope).select{|pin| visibility.include?(pin.visibility)}
127
- # @todo This needs more rules. Probably need to update YardObject for it.
128
- return result if result.empty?
129
- return result unless method_name == 'new' and result.first.path == 'Class#new'
130
- result.unshift virtual_new_pin(result.first, context_pin)
131
- result
132
- end
133
-
134
- # Word and context matching rules for ApiMap source pins.
135
- #
136
- # @return [Boolean]
137
- def word_matches_context? word, namespace, scope, pin
138
- return false unless word == pin.name
139
- return true if pin.kind == Pin::NAMESPACE and pin.path == namespace and scope == :class
140
- return true if pin.kind == Pin::METHOD and pin.namespace == namespace and pin.scope == scope
141
- # @todo Handle instance variables, class variables, etc. in various ways
142
- pin.namespace == namespace and pin.scope == scope
143
- end
144
-
145
- # Fully qualify the namespace in a type.
146
- #
147
- # @return [String]
148
- def qualify type, context
149
- rns, rsc = extract_namespace_and_scope(type)
150
- res = api_map.qualify(rns, context)
151
- return res if rsc == :instance
152
- type.sub(/<#{rns}>/, "<#{res}>")
153
- end
154
-
155
- # Extract a namespace and a scope from a pin. For now, the pin must
156
- # be either a namespace, a method, or a block.
157
- #
158
- # @return [Array] The namespace (String) and scope (Symbol).
159
- def extract_namespace_and_scope_from_pin pin
160
- return [pin.namespace, pin.scope] if pin.kind == Pin::METHOD
161
- return [pin.path, :class] if pin.kind == Pin::NAMESPACE
162
- # @todo Is :class appropriate for blocks?
163
- return [pin.namespace, :class] if pin.kind == Pin::BLOCK
164
- raise "Unable to extract namespace and scope from #{pin.path}"
165
- end
166
-
167
- # Determine whether or not the word represents a variable. This method
168
- # is used to keep the probe from performing unnecessary constant and
169
- # method searches.
170
- #
171
- # @return [Boolean]
172
- def variable_name? word
173
- word.start_with?('@') or word.start_with?('$')
174
- end
175
-
176
- # Create a `new` pin to facilitate type inference. This is necessary for
177
- # classes from YARD and classes in the namespace that do not have an
178
- # `initialize` method.
179
- #
180
- # @return [Pin::Method]
181
- def virtual_new_pin new_pin, context_pin
182
- pin = Pin::Method.new(new_pin.location, context_pin.path, new_pin.name, '', :class, new_pin.visibility, new_pin.parameters)
183
- # @todo Smelly instance variable access.
184
- pin.instance_variable_set(:@return_complex_types, ComplexType.parse(context_pin.path))
185
- pin
186
- end
187
-
188
- # @param pin [Solargraph::Pin::Base]
189
- # @param locals [Array<Solargraph::Pin::Base>]
190
- # @return [String]
191
- def resolve_pin_type pin, locals
192
- return pin.return_type unless pin.return_type.nil?
193
- return pin.namespace if pin.kind == Pin::METHOD and pin.name == 'new' and pin.scope == :class
194
- return resolve_block_parameter(pin, locals) if pin.kind == Pin::BLOCK_PARAMETER
195
- return resolve_method_parameter(pin) if pin.is_a?(Pin::MethodParameter)
196
- return resolve_variable(pin, locals) if pin.variable?
197
- nil
198
- end
199
-
200
- def resolve_block_parameter pin, locals
201
- return pin.return_type unless pin.return_type.nil?
202
- signature = pin.block.receiver
203
- # @todo Not sure if assuming the first pin is good here
204
- meth = infer_signature_pins(signature, pin.block, locals).first
205
- return nil if meth.nil?
206
- if (Solargraph::CoreFills::METHODS_WITH_YIELDPARAM_SUBTYPES.include?(meth.path))
207
- base = signature.split('.')[0..-2].join('.')
208
- return nil if base.nil? or base.empty?
209
- # @todo Not sure if assuming the first pin is good here
210
- bmeth = infer_signature_pins(base, pin.block, locals).first
211
- return nil if bmeth.nil?
212
- btype = bmeth.return_type
213
- btype = infer_signature_type(bmeth.signature, pin.block, locals) if btype.nil? and bmeth.variable?
214
- subtypes = get_subtypes(btype)
215
- return nil if subtypes.nil?
216
- return subtypes[0]
217
- else
218
- yps = meth.docstring.tags(:yieldparam)
219
- unless yps[pin.index].nil? or yps[pin.index].types.nil? or yps[pin.index].types.empty?
220
- return yps[pin.index].types[0]
221
- end
222
- end
223
- nil
224
- end
225
-
226
- def resolve_method_parameter pin
227
- matches = api_map.get_method_stack(pin.namespace, pin.context.name, scope: pin.scope)
228
- matches.each do |m|
229
- next unless pin.context.parameters == m.parameters
230
- tag = m.docstring.tags(:param).select{|t| t.name == pin.name}.first
231
- next if tag.nil? or tag.types.nil?
232
- return tag.types[0]
233
- end
234
- nil
235
- end
236
-
237
- def resolve_variable(pin, locals)
238
- return nil if pin.nil_assignment?
239
- # @todo Do we need the locals here?
240
- return infer_signature_type(pin.signature, pin.context, locals)
241
- end
242
-
243
- def get_subtypes type
244
- return nil if type.nil?
245
- match = type.match(/<([a-z0-9_:, ]*)>/i)
246
- return [] if match.nil?
247
- match[1].split(',').map(&:strip)
248
- end
249
- end
250
- end
251
- end