solargraph 0.27.1 → 0.28.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +8 -17
  3. data/lib/solargraph/api_map.rb +4 -3
  4. data/lib/solargraph/api_map/cache.rb +5 -5
  5. data/lib/solargraph/api_map/source_to_yard.rb +3 -2
  6. data/lib/solargraph/api_map/store.rb +25 -13
  7. data/lib/solargraph/complex_type.rb +3 -0
  8. data/lib/solargraph/diagnostics/update_errors.rb +21 -1
  9. data/lib/solargraph/language_server/host.rb +4 -3
  10. data/lib/solargraph/language_server/message/text_document/rename.rb +1 -1
  11. data/lib/solargraph/library.rb +12 -4
  12. data/lib/solargraph/pin.rb +5 -1
  13. data/lib/solargraph/pin/base.rb +0 -10
  14. data/lib/solargraph/pin/conversions.rb +1 -1
  15. data/lib/solargraph/pin/documenting.rb +0 -9
  16. data/lib/solargraph/pin/duck_method.rb +1 -1
  17. data/lib/solargraph/pin/keyword.rb +0 -5
  18. data/lib/solargraph/pin/namespace.rb +3 -16
  19. data/lib/solargraph/pin/reference.rb +13 -26
  20. data/lib/solargraph/pin/reference/extend.rb +11 -0
  21. data/lib/solargraph/pin/reference/include.rb +11 -0
  22. data/lib/solargraph/pin/reference/require.rb +15 -0
  23. data/lib/solargraph/pin/reference/superclass.rb +11 -0
  24. data/lib/solargraph/pin/symbol.rb +0 -4
  25. data/lib/solargraph/pin/yard_pin/namespace.rb +14 -14
  26. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -4
  27. data/lib/solargraph/position.rb +7 -0
  28. data/lib/solargraph/source.rb +7 -28
  29. data/lib/solargraph/source/chain.rb +0 -1
  30. data/lib/solargraph/source/chain/call.rb +1 -1
  31. data/lib/solargraph/source/chain/constant.rb +13 -4
  32. data/lib/solargraph/source/change.rb +7 -1
  33. data/lib/solargraph/source/cursor.rb +1 -5
  34. data/lib/solargraph/source/node_chainer.rb +5 -6
  35. data/lib/solargraph/source/source_chainer.rb +14 -12
  36. data/lib/solargraph/source_map.rb +5 -6
  37. data/lib/solargraph/source_map/clip.rb +16 -29
  38. data/lib/solargraph/source_map/mapper.rb +26 -21
  39. data/lib/solargraph/version.rb +1 -1
  40. data/lib/solargraph/workspace.rb +1 -2
  41. data/lib/solargraph/workspace/config.rb +10 -5
  42. data/lib/solargraph/yard_map.rb +3 -1
  43. metadata +6 -3
  44. data/lib/solargraph/source/chain/definition.rb +0 -20
@@ -0,0 +1,11 @@
1
+ module Solargraph
2
+ module Pin
3
+ class Reference
4
+ class Extend < Reference
5
+ def kind
6
+ Pin::EXTEND_REFERENCE
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Solargraph
2
+ module Pin
3
+ class Reference
4
+ class Include < Reference
5
+ def kind
6
+ Pin::INCLUDE_REFERENCE
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Solargraph
2
+ module Pin
3
+ class Reference
4
+ class Require < Reference
5
+ def initialize location, name
6
+ super(location, '', name)
7
+ end
8
+
9
+ def kind
10
+ Pin::REQUIRE_REFERENCE
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Solargraph
2
+ module Pin
3
+ class Reference
4
+ class Superclass < Reference
5
+ def kind
6
+ Pin::SUPERCLASS_REFERENCE
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -20,10 +20,6 @@ module Solargraph
20
20
  ''
21
21
  end
22
22
 
23
- def identifier
24
- name
25
- end
26
-
27
23
  def completion_item_kind
28
24
  Solargraph::LanguageServer::CompletionItemKinds::KEYWORD
29
25
  end
@@ -9,20 +9,20 @@ module Solargraph
9
9
  # @todo This method of superclass detection is a bit of a hack. If
10
10
  # the superclass is a Proxy, it is assumed to be undefined in its
11
11
  # yardoc and converted to a fully qualified namespace.
12
- if code_object.is_a?(YARD::CodeObjects::ClassObject) && code_object.superclass
13
- if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
14
- superclass = "::#{code_object.superclass}"
15
- else
16
- superclass = code_object.superclass.to_s
17
- end
18
- end
19
- super(location, code_object.namespace.to_s, code_object.name.to_s, comments_from(code_object), namespace_type(code_object), code_object.visibility, superclass)
20
- code_object.class_mixins.each do |m|
21
- extend_references.push Pin::Reference.new(location, path, m.path)
22
- end
23
- code_object.instance_mixins.each do |m|
24
- include_references.push Pin::Reference.new(location, path, m.path)
25
- end
12
+ # if code_object.is_a?(YARD::CodeObjects::ClassObject) && code_object.superclass
13
+ # if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
14
+ # superclass = "::#{code_object.superclass}"
15
+ # else
16
+ # superclass = code_object.superclass.to_s
17
+ # end
18
+ # end
19
+ super(location, code_object.namespace.to_s, code_object.name.to_s, comments_from(code_object), namespace_type(code_object), code_object.visibility)
20
+ # code_object.class_mixins.each do |m|
21
+ # extend_references.push Pin::Reference.new(location, path, m.path)
22
+ # end
23
+ # code_object.instance_mixins.each do |m|
24
+ # include_references.push Pin::Reference.new(location, path, m.path)
25
+ # end
26
26
  end
27
27
 
28
28
  private
@@ -2,10 +2,6 @@ module Solargraph
2
2
  module Pin
3
3
  module YardPin
4
4
  module YardMixin
5
- def yard_pin?
6
- true
7
- end
8
-
9
5
  private
10
6
 
11
7
  def comments_from code_object
@@ -89,6 +89,13 @@ module Solargraph
89
89
  Position.new(line, character)
90
90
  end
91
91
 
92
+ # A helper method for generating positions from arrays of integers. The
93
+ # original parameter is returned if it is already a position.
94
+ #
95
+ # @raise [ArgumentError] if the object cannot be converted to a position.
96
+ #
97
+ # @param object [Position, Array(Integer, Integer)]
98
+ # @return [Position]
92
99
  def self.normalize object
93
100
  return object if object.is_a?(Position)
94
101
  return Position.new(object[0], object[1]) if object.is_a?(Array)
@@ -97,24 +97,19 @@ module Solargraph
97
97
  def synchronize updater
98
98
  raise 'Invalid synchronization' unless updater.filename == filename
99
99
  real_code = updater.write(@code)
100
- incr_code = updater.write(@code, true)
101
100
  if real_code == @code
102
101
  @version = updater.version
103
102
  return self
104
103
  end
105
- synced = Source.new(incr_code, filename)
104
+ synced = Source.new(real_code, filename)
106
105
  if synced.parsed?
107
- synced.code = real_code
108
- if synced.repaired?
109
- synced.error_ranges.concat combine_errors(error_ranges + updater.changes.map(&:range))
110
- end
111
- else
112
- new_repair = updater.repair(@repaired)
113
- synced = Source.new(new_repair, filename)
114
- synced.error_ranges.concat combine_errors(error_ranges + updater.changes.map(&:range))
115
- synced.parsed = false
116
- synced.code = real_code
106
+ synced.version = updater.version
107
+ return synced
117
108
  end
109
+ incr_code = updater.repair(@repaired)
110
+ synced = Source.new(incr_code, filename)
111
+ synced.error_ranges.concat (error_ranges + updater.changes.map(&:range))
112
+ synced.code = real_code
118
113
  synced.version = updater.version
119
114
  synced
120
115
  end
@@ -226,22 +221,6 @@ module Solargraph
226
221
  result
227
222
  end
228
223
 
229
- # @param ranges [Array<Range>]
230
- # @return [Array<Range>]
231
- def combine_errors ranges
232
- result = []
233
- lines = []
234
- ranges.sort{|a, b| a.start.line <=> b.start.line}.each do |rng|
235
- next if rng.nil? || lines.include?(rng.start.line)
236
- lines.push rng.start.line
237
- next if comment_at?(rng.start) || rng.start.line >= code.lines.length
238
- fcol = code.lines[rng.start.line].index(/[^\s]/) || 0
239
- ecol = code.lines[rng.start.line].length
240
- result.push Range.from_to(rng.start.line, fcol, rng.start.line, ecol)
241
- end
242
- result
243
- end
244
-
245
224
  protected
246
225
 
247
226
  # @return [Integer]
@@ -12,7 +12,6 @@ module Solargraph
12
12
  autoload :InstanceVariable, 'solargraph/source/chain/instance_variable'
13
13
  autoload :GlobalVariable, 'solargraph/source/chain/global_variable'
14
14
  autoload :Literal, 'solargraph/source/chain/literal'
15
- autoload :Definition, 'solargraph/source/chain/definition'
16
15
  autoload :Head, 'solargraph/source/chain/head'
17
16
 
18
17
  UNDEFINED_CALL = Chain::Call.new('<undefined>')
@@ -61,7 +61,7 @@ module Solargraph
61
61
  end
62
62
 
63
63
  def external_constructor? pin, context
64
- pin.path == 'Class#new' || (pin.name == 'new' && pin.scope == :class && pin.context != context)
64
+ pin.path == 'Class#new' || (pin.name == 'new' && pin.scope == :class && pin.return_type != context)
65
65
  end
66
66
 
67
67
  # @param pin [Pin::Method]
@@ -8,10 +8,19 @@ module Solargraph
8
8
 
9
9
  def resolve api_map, name_pin, locals
10
10
  return [Pin::ROOT_PIN] if word.empty?
11
- parts = word.split('::')
12
- last = parts.pop
13
- first = parts.join('::').to_s
14
- api_map.get_constants(first, name_pin.context.namespace).select{|p| p.name == last}
11
+ if word.start_with?('::')
12
+ context = ''
13
+ bottom = word[2..-1]
14
+ else
15
+ context = name_pin.context.namespace
16
+ bottom = word
17
+ end
18
+ if bottom.include?('::')
19
+ ns = bottom.split('::')[0..-2].join('::')
20
+ else
21
+ ns = ''
22
+ end
23
+ api_map.get_constants(ns, context).select{|p| p.path.end_with?(bottom)}
15
24
  end
16
25
  end
17
26
  end
@@ -55,7 +55,13 @@ module Solargraph
55
55
  if range.nil?
56
56
  fixed
57
57
  else
58
- commit text, fixed
58
+ result = commit text, fixed
59
+ off = Position.to_offset(text, range.start)
60
+ match = result[0..off].match(/[\.:]+\z/)
61
+ if match
62
+ result = result[0..off].sub(/#{match[0]}\z/, ' ' * match[0].length) + result[off..-1]
63
+ end
64
+ result
59
65
  end
60
66
  end
61
67
 
@@ -14,11 +14,7 @@ module Solargraph
14
14
  # @param position [Position, Array(Integer, Integer)]
15
15
  def initialize source, position
16
16
  @source = source
17
- @position = if position.is_a?(Array)
18
- Position.new(position[0], position[1])
19
- else
20
- position
21
- end
17
+ @position = Position.normalize(position)
22
18
  end
23
19
 
24
20
  # @return [String]
@@ -73,10 +73,11 @@ module Solargraph
73
73
  elsif n.type == :const
74
74
  # result.push Chain::Constant.new(unpack_name(n))
75
75
  const = unpack_name(n)
76
- parts = const.split('::')
77
- last = parts.pop
78
- result.push Chain::Constant.new(parts.join('::')) unless parts.empty?
79
- result.push Chain::Constant.new(last)
76
+ # parts = const.split('::')
77
+ # last = parts.pop
78
+ # result.push Chain::Constant.new(parts.join('::')) unless parts.empty?
79
+ # result.push Chain::Constant.new(last)
80
+ result.push Chain::Constant.new(const)
80
81
  elsif [:lvar, :lvasgn].include?(n.type)
81
82
  result.push Chain::Call.new(n.children[0].to_s)
82
83
  elsif [:ivar, :ivasgn].include?(n.type)
@@ -86,8 +87,6 @@ module Solargraph
86
87
  elsif [:gvar, :gvasgn].include?(n.type)
87
88
  result.push Chain::GlobalVariable.new(n.children[0].to_s)
88
89
  elsif [:class, :module, :def, :defs].include?(n.type)
89
- # location = Solargraph::Location.new(@filename, Range.from_to(n.loc.expression.line, n.loc.expression.column, n.loc.expression.last_line, n.loc.expression.last_column))
90
- # result.push Chain::Definition.new(location)
91
90
  # @todo Undefined or what?
92
91
  result.push Chain::UNDEFINED_CALL
93
92
  else
@@ -35,13 +35,15 @@ module Solargraph
35
35
  # @return [Source::Chain]
36
36
  def chain
37
37
  return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
38
+ # return Chain.new([Chain::UNDEFINED_CALL]) unless infer_literal_node_type(source.node_at(position.line, position.column)).nil?
38
39
  begin
39
- if source.repaired? && source.parsed?
40
- node = source.node_at(fixed_position.line, fixed_position.column)
41
- elsif source.parsed?
40
+ return Chain.new([]) if phrase.end_with?('..')
41
+ if !source.repaired? && source.parsed?
42
42
  node = source.node_at(position.line, position.column)
43
43
  else
44
- node = Source.parse(fixed_phrase)
44
+ node = nil
45
+ node = source.node_at(fixed_position.line, fixed_position.column) unless source.error_ranges.any?{|r| r.include?(fixed_position)}
46
+ node = Source.parse(fixed_phrase) if node.nil?
45
47
  end
46
48
  rescue Parser::SyntaxError
47
49
  return Chain.new([Chain::UNDEFINED_CALL])
@@ -54,15 +56,13 @@ module Solargraph
54
56
  elsif end_of_phrase.strip == '::'
55
57
  chain.links.push Chain::UNDEFINED_CONSTANT
56
58
  end
57
- elsif end_of_phrase.strip == '::'
58
- chain.links.pop
59
- chain.links.push Chain::UNDEFINED_CONSTANT
60
59
  end
61
60
  chain
62
61
  end
63
62
 
64
63
  private
65
64
 
65
+ # @return [Position]
66
66
  attr_reader :position
67
67
 
68
68
  # The zero-based line number of the fragment's location.
@@ -78,18 +78,22 @@ module Solargraph
78
78
  # @return [Solargraph::Source]
79
79
  attr_reader :source
80
80
 
81
+ # @return [String]
81
82
  def phrase
82
83
  @phrase ||= source.code[signature_data[0]..offset-1]
83
84
  end
84
85
 
86
+ # @return [String]
85
87
  def fixed_phrase
86
88
  @fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
87
89
  end
88
90
 
91
+ # @return [Position]
89
92
  def fixed_position
90
93
  @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
91
94
  end
92
95
 
96
+ # @return [String]
93
97
  def end_of_phrase
94
98
  @end_of_phrase ||= begin
95
99
  match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
@@ -108,11 +112,6 @@ module Solargraph
108
112
  @column
109
113
  end
110
114
 
111
- # @return [Position]
112
- def position
113
- @position ||= Position.new(line, column)
114
- end
115
-
116
115
  # True if the current offset is inside a string.
117
116
  #
118
117
  # @return [Boolean]
@@ -126,6 +125,9 @@ module Solargraph
126
125
  @offset ||= get_offset(line, column)
127
126
  end
128
127
 
128
+ # @param line [Integer]
129
+ # @param column [Integer]
130
+ # @return [Integer]
129
131
  def get_offset line, column
130
132
  Position.line_char_to_offset(@source.code, line, column)
131
133
  end
@@ -15,16 +15,11 @@ module Solargraph
15
15
  # @return [Array<Pin::Base>]
16
16
  attr_reader :locals
17
17
 
18
- # @return [Array<Pin::Reference>]
19
- attr_reader :requires
20
-
21
- def initialize source, pins, locals, requires, symbols
18
+ def initialize source, pins, locals
22
19
  # HACK: Keep the library from changing this
23
20
  @source = source.dup
24
21
  @pins = pins
25
22
  @locals = locals
26
- @requires = requires
27
- @pins.concat symbols
28
23
  end
29
24
 
30
25
  def filename
@@ -35,6 +30,10 @@ module Solargraph
35
30
  source.code
36
31
  end
37
32
 
33
+ def requires
34
+ @requires ||= pins.select{|p| p.kind == Pin::REQUIRE_REFERENCE}
35
+ end
36
+
38
37
  # @param position [Position]
39
38
  # @return [Boolean]
40
39
  def string_at? position
@@ -1,11 +1,12 @@
1
1
  module Solargraph
2
2
  class SourceMap
3
+ # A static analysis tool for obtaining definitions, completions,
4
+ # signatures, and type inferences from a cursor.
5
+ #
3
6
  class Clip
4
7
  # @param api_map [ApiMap]
5
8
  # @param cursor [Source::Cursor]
6
9
  def initialize api_map, cursor
7
- # @todo Just some temporary stuff while I make sure this works
8
- raise "Not a cursor: #{cursor.class}" unless cursor.is_a?(Source::Cursor)
9
10
  @api_map = api_map
10
11
  @cursor = cursor
11
12
  end
@@ -36,7 +37,7 @@ module Solargraph
36
37
  elsif cursor.word.start_with?('$')
37
38
  return package_completions(api_map.get_global_variable_pins)
38
39
  end
39
- result.concat prefer_non_nil_variables(locals)
40
+ result.concat locals
40
41
  result.concat api_map.get_constants('', context_pin.context.namespace)
41
42
  result.concat api_map.get_methods(context_pin.context.namespace, scope: context_pin.context.scope, visibility: [:public, :private, :protected])
42
43
  result.concat api_map.get_methods('Kernel')
@@ -53,17 +54,11 @@ module Solargraph
53
54
  clip.define.select{|pin| pin.kind == Pin::METHOD}
54
55
  end
55
56
 
57
+ # @return [ComplexType]
56
58
  def infer
57
59
  cursor.chain.infer(api_map, context_pin, locals)
58
60
  end
59
61
 
60
- # The context at the current position.
61
- #
62
- # @return [Pin::Base]
63
- def context_pin
64
- @context ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
65
- end
66
-
67
62
  # Get an array of all the locals that are visible from the cursors's
68
63
  # position. Locals can be local variables, method parameters, or block
69
64
  # parameters. The array starts with the nearest local pin.
@@ -93,31 +88,23 @@ module Solargraph
93
88
  @block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
94
89
  end
95
90
 
96
- # @param cursor [cursor]
91
+ # The context at the current position.
92
+ #
93
+ # @return [Pin::Base]
94
+ def context_pin
95
+ @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
96
+ end
97
+
97
98
  # @param result [Array<Pin::Base>]
98
99
  # @return [Completion]
99
100
  def package_completions result
100
101
  frag_start = cursor.start_of_word.to_s.downcase
101
- filtered = result.uniq(&:name).select{|s| s.name.downcase.start_with?(frag_start) and (s.kind != Pin::METHOD or s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))}
102
+ filtered = result.uniq(&:name).select { |s|
103
+ s.name.downcase.start_with?(frag_start) &&
104
+ (s.kind != Pin::METHOD || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
105
+ }
102
106
  Completion.new(filtered, cursor.range)
103
107
  end
104
-
105
- # Sort an array of pins to put nil or undefined variables last.
106
- #
107
- # @param pins [Array<Pin::Base>]
108
- # @return [Array<Pin::Base>]
109
- def prefer_non_nil_variables pins
110
- result = []
111
- nil_pins = []
112
- pins.each do |pin|
113
- if pin.variable? and pin.nil_assignment?
114
- nil_pins.push pin
115
- else
116
- result.push pin
117
- end
118
- end
119
- result + nil_pins
120
- end
121
108
  end
122
109
  end
123
110
  end