solargraph 0.26.1 → 0.27.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +5 -2
  3. data/lib/solargraph/api_map.rb +236 -234
  4. data/lib/solargraph/api_map/store.rb +18 -53
  5. data/lib/solargraph/bundle.rb +22 -0
  6. data/lib/solargraph/complex_type.rb +9 -5
  7. data/lib/solargraph/complex_type/type_methods.rb +113 -0
  8. data/lib/solargraph/complex_type/unique_type.rb +35 -0
  9. data/lib/solargraph/core_fills.rb +1 -0
  10. data/lib/solargraph/diagnostics.rb +6 -4
  11. data/lib/solargraph/diagnostics/base.rb +3 -0
  12. data/lib/solargraph/diagnostics/require_not_found.rb +2 -1
  13. data/lib/solargraph/diagnostics/rubocop.rb +21 -6
  14. data/lib/solargraph/diagnostics/type_not_defined.rb +4 -3
  15. data/lib/solargraph/diagnostics/update_errors.rb +18 -0
  16. data/lib/solargraph/language_server/host.rb +90 -222
  17. data/lib/solargraph/language_server/host/cataloger.rb +68 -0
  18. data/lib/solargraph/language_server/host/diagnoser.rb +85 -0
  19. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +35 -24
  20. data/lib/solargraph/language_server/message/text_document/completion.rb +6 -8
  21. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
  22. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +0 -1
  23. data/lib/solargraph/language_server/transport/socket.rb +4 -6
  24. data/lib/solargraph/language_server/transport/stdio.rb +4 -6
  25. data/lib/solargraph/library.rb +152 -99
  26. data/lib/solargraph/live_map.rb +1 -1
  27. data/lib/solargraph/location.rb +28 -0
  28. data/lib/solargraph/pin.rb +2 -0
  29. data/lib/solargraph/pin/attribute.rb +26 -12
  30. data/lib/solargraph/pin/base.rb +15 -35
  31. data/lib/solargraph/pin/base_variable.rb +7 -15
  32. data/lib/solargraph/pin/block.rb +5 -9
  33. data/lib/solargraph/pin/block_parameter.rb +9 -7
  34. data/lib/solargraph/pin/conversions.rb +5 -5
  35. data/lib/solargraph/pin/duck_method.rb +1 -1
  36. data/lib/solargraph/pin/instance_variable.rb +0 -4
  37. data/lib/solargraph/pin/keyword.rb +4 -0
  38. data/lib/solargraph/pin/localized.rb +5 -3
  39. data/lib/solargraph/pin/method.rb +11 -0
  40. data/lib/solargraph/pin/namespace.rb +7 -3
  41. data/lib/solargraph/pin/proxy_type.rb +3 -7
  42. data/lib/solargraph/pin/reference.rb +2 -2
  43. data/lib/solargraph/pin/symbol.rb +1 -1
  44. data/lib/solargraph/pin/yard_pin/method.rb +2 -2
  45. data/lib/solargraph/pin/yard_pin/namespace.rb +16 -7
  46. data/lib/solargraph/position.rb +103 -0
  47. data/lib/solargraph/range.rb +70 -0
  48. data/lib/solargraph/source.rb +159 -328
  49. data/lib/solargraph/source/chain.rb +38 -55
  50. data/lib/solargraph/source/chain/call.rb +47 -29
  51. data/lib/solargraph/source/chain/class_variable.rb +2 -2
  52. data/lib/solargraph/source/chain/constant.rb +3 -3
  53. data/lib/solargraph/source/chain/definition.rb +7 -3
  54. data/lib/solargraph/source/chain/global_variable.rb +1 -1
  55. data/lib/solargraph/source/chain/head.rb +22 -9
  56. data/lib/solargraph/source/chain/instance_variable.rb +2 -2
  57. data/lib/solargraph/source/chain/link.rb +4 -4
  58. data/lib/solargraph/source/chain/literal.rb +1 -1
  59. data/lib/solargraph/source/chain/variable.rb +2 -2
  60. data/lib/solargraph/source/change.rb +0 -6
  61. data/lib/solargraph/source/cursor.rb +161 -0
  62. data/lib/solargraph/source/encoding_fixes.rb +1 -1
  63. data/lib/solargraph/source/node_chainer.rb +28 -21
  64. data/lib/solargraph/source/node_methods.rb +1 -1
  65. data/lib/solargraph/source/source_chainer.rb +217 -0
  66. data/lib/solargraph/source_map.rb +138 -0
  67. data/lib/solargraph/source_map/clip.rb +123 -0
  68. data/lib/solargraph/{source → source_map}/completion.rb +3 -3
  69. data/lib/solargraph/{source → source_map}/mapper.rb +143 -41
  70. data/lib/solargraph/version.rb +1 -1
  71. data/lib/solargraph/workspace.rb +13 -20
  72. data/lib/solargraph/yard_map.rb +77 -48
  73. metadata +17 -11
  74. data/lib/solargraph/basic_type.rb +0 -33
  75. data/lib/solargraph/basic_type_methods.rb +0 -111
  76. data/lib/solargraph/source/call_chainer.rb +0 -273
  77. data/lib/solargraph/source/fragment.rb +0 -342
  78. data/lib/solargraph/source/location.rb +0 -23
  79. data/lib/solargraph/source/position.rb +0 -95
  80. data/lib/solargraph/source/range.rb +0 -64
@@ -3,41 +3,12 @@ require 'set'
3
3
  module Solargraph
4
4
  class ApiMap
5
5
  class Store
6
- # @param sources [Array<Solargraph::Source>]
7
- # @param yard_pins [Array<Solargraph::Pin::Base>]
8
- def initialize sources, yard_pins
9
- inner_update sources
10
- pins.concat yard_pins
11
- index
12
- end
13
-
14
6
  # @return [Array<Solargraph::Pin::Base>]
15
- def pins
16
- @pins ||= []
17
- end
7
+ attr_reader :pins
18
8
 
19
- # @param *sources [Array<Solargraph::Source>]
20
- # @return [void]
21
- def remove *sources
22
- sources.each do |source|
23
- pins.delete_if { |pin| !pin.yard_pin? and pin.filename == source.filename }
24
- symbols.delete_if { |pin| pin.filename == source.filename }
25
- end
26
- index
27
- end
28
-
29
- # @param *sources [Array<Solargraph::Source>]
30
- # @return [void]
31
- def update *sources
32
- inner_update sources
33
- index
34
- end
35
-
36
- # @param yard_pins [Array<Solargraph::Pin::Base>]
37
- # @return [void]
38
- def update_yard yard_pins
39
- pins.delete_if(&:yard_pin?)
40
- pins.concat yard_pins
9
+ # @param pins [Array<Solargraph::Source>]
10
+ def initialize pins = []
11
+ @pins = pins
41
12
  index
42
13
  end
43
14
 
@@ -56,17 +27,10 @@ module Solargraph
56
27
  # @return [Array<Solargraph::Pin::Base>]
57
28
  def get_methods fqns, scope: :instance, visibility: [:public]
58
29
  namespace_children(fqns).select{ |pin|
59
- pin.kind == Pin::METHOD and (pin.scope == scope or fqns == '') and visibility.include?(pin.visibility)
30
+ [Pin::METHOD, Pin::ATTRIBUTE].include?(pin.kind) and (pin.scope == scope or fqns == '') and visibility.include?(pin.visibility)
60
31
  }
61
32
  end
62
33
 
63
- # @param fqns [String]
64
- # @param scope [Symbol]
65
- # @return [Array<Solargraph::Pin::Base>]
66
- def get_attrs fqns, scope
67
- namespace_children(fqns).select{ |pin| pin.kind == Pin::ATTRIBUTE and pin.scope == scope }
68
- end
69
-
70
34
  # @param fqns [String]
71
35
  # @return [String]
72
36
  def get_superclass fqns
@@ -110,7 +74,7 @@ module Solargraph
110
74
  # @param scope [Symbol] :class or :instance
111
75
  # @return [Array<Solargraph::Pin::Base>]
112
76
  def get_instance_variables(fqns, scope = :instance)
113
- namespace_children(fqns).select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.scope == scope}
77
+ namespace_children(fqns).select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.context.scope == scope}
114
78
  end
115
79
 
116
80
  # @param fqns [String]
@@ -145,6 +109,16 @@ module Solargraph
145
109
  @method_pins ||= pins.select{|p| p.kind == Pin::METHOD or p.kind == Pin::ATTRIBUTE}
146
110
  end
147
111
 
112
+ # @param fqns [String]
113
+ # @return [Array<String>]
114
+ def domains(fqns)
115
+ result = []
116
+ fqns_pins(fqns).each do |nspin|
117
+ result.concat nspin.domains
118
+ end
119
+ result
120
+ end
121
+
148
122
  private
149
123
 
150
124
  # @param fqns [String]
@@ -182,26 +156,17 @@ module Solargraph
182
156
  def index
183
157
  namespace_map.clear
184
158
  namespaces.clear
159
+ symbols.clear
185
160
  namespace_map[''] = []
186
161
  pins.each do |pin|
187
162
  namespace_map[pin.namespace] ||= []
188
163
  namespace_map[pin.namespace].push pin
189
164
  namespaces.add pin.path if pin.kind == Pin::NAMESPACE and !pin.path.empty?
165
+ symbols.push pin if pin.kind == Pin::SYMBOL
190
166
  end
191
167
  @namespace_pins = nil
192
168
  @method_pins = nil
193
169
  end
194
-
195
- # @param sources [Array<Solargraph::Source>]
196
- # @return [void]
197
- def inner_update sources
198
- sources.each do |source|
199
- pins.delete_if { |pin| !pin.yard_pin? and pin.filename == source.filename }
200
- symbols.delete_if { |pin| pin.filename == source.filename }
201
- pins.concat source.pins
202
- symbols.concat source.symbols
203
- end
204
- end
205
170
  end
206
171
  end
207
172
  end
@@ -0,0 +1,22 @@
1
+ module Solargraph
2
+ class Bundle
3
+ # @return [Array<Source>]
4
+ attr_reader :sources
5
+
6
+ # @return [Array<String>]
7
+ attr_reader :required
8
+
9
+ # @return [Array<String>]
10
+ attr_reader :load_paths
11
+
12
+ # @return [YardMap]
13
+ attr_reader :yard_map
14
+
15
+ def initialize sources: [], required: [], load_paths: [], yard_map: YardMap.new
16
+ @sources = sources
17
+ @required = required
18
+ @load_paths = load_paths
19
+ @yard_map = yard_map
20
+ end
21
+ end
22
+ end
@@ -4,8 +4,11 @@ module Solargraph
4
4
  # including the module. One possibility:
5
5
  #
6
6
  # @!parse
7
- # include BasicTypeMethods
7
+ # include TypeMethods
8
8
 
9
+ autoload :TypeMethods, 'solargraph/complex_type/type_methods'
10
+ autoload :UniqueType, 'solargraph/complex_type/unique_type'
11
+
9
12
  def initialize types = [ComplexType::UNDEFINED]
10
13
  super()
11
14
  concat types
@@ -24,7 +27,7 @@ module Solargraph
24
27
  end
25
28
 
26
29
  def respond_to_missing?(name, include_private = false)
27
- BasicTypeMethods.public_instance_methods.include?(name) || super
30
+ TypeMethods.public_instance_methods.include?(name) || super
28
31
  end
29
32
 
30
33
  def to_s
@@ -71,7 +74,7 @@ module Solargraph
71
74
  subtype_string += char
72
75
  elsif base.end_with?('=')
73
76
  raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
74
- types.push ComplexType.new([BasicType.new(base[0..-2].strip)])
77
+ types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])
75
78
  key_types = types
76
79
  types = []
77
80
  base = ''
@@ -99,7 +102,7 @@ module Solargraph
99
102
  raise ComplexTypeError, "Invalid close in type #{type_string}" if paren_stack < 0
100
103
  next
101
104
  elsif char == ',' and point_stack == 0 and curly_stack == 0 and paren_stack == 0
102
- types.push ComplexType.new([BasicType.new(base.strip, subtype_string.strip)])
105
+ types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])
103
106
  base = ''
104
107
  subtype_string = ''
105
108
  next
@@ -113,7 +116,7 @@ module Solargraph
113
116
  base.strip!
114
117
  subtype_string.strip!
115
118
  raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 or curly_stack != 0 or paren_stack != 0
116
- types.push ComplexType.new([BasicType.new(base, subtype_string)])
119
+ types.push ComplexType.new([UniqueType.new(base, subtype_string)])
117
120
  end
118
121
  unless key_types.nil?
119
122
  raise ComplexTypeError, "Invalid use of key/value parameters" unless partial
@@ -129,5 +132,6 @@ module Solargraph
129
132
  VOID = ComplexType.parse('void')
130
133
  UNDEFINED = ComplexType.parse('undefined')
131
134
  SYMBOL = ComplexType.parse('Symbol')
135
+ ROOT = ComplexType.parse('Class<>')
132
136
  end
133
137
  end
@@ -0,0 +1,113 @@
1
+ module Solargraph
2
+ class ComplexType
3
+ module TypeMethods
4
+ # @return [String]
5
+ attr_reader :name
6
+
7
+ # @return [String]
8
+ attr_reader :substring
9
+
10
+ # @return [String]
11
+ attr_reader :tag
12
+
13
+ # @return [Array<ComplexType>]
14
+ attr_reader :subtypes
15
+
16
+ # @return [Boolean]
17
+ def duck_type?
18
+ @duck_type ||= name.start_with?('#')
19
+ end
20
+
21
+ # @return [Boolean]
22
+ def nil_type?
23
+ @nil_type ||= (name.downcase == 'nil')
24
+ end
25
+
26
+ # @return [Boolean]
27
+ def parameters?
28
+ !substring.empty?
29
+ end
30
+
31
+ def void?
32
+ name == 'void'
33
+ end
34
+
35
+ def defined?
36
+ !undefined?
37
+ end
38
+
39
+ def undefined?
40
+ name == 'undefined'
41
+ end
42
+
43
+ # @return [Boolean]
44
+ def list_parameters?
45
+ substring.start_with?('<')
46
+ end
47
+
48
+ # @return [Boolean]
49
+ def fixed_parameters?
50
+ substring.start_with?('(')
51
+ end
52
+
53
+ # @return [Boolean]
54
+ def hash_parameters?
55
+ substring.start_with?('{')
56
+ end
57
+
58
+ # @return [Array<ComplexType>]
59
+ def value_types
60
+ @subtypes
61
+ end
62
+
63
+ # @return [Array<ComplexType>]
64
+ def key_types
65
+ @key_types
66
+ end
67
+
68
+ # @return [String]
69
+ def namespace
70
+ @namespace ||= 'Object' if duck_type?
71
+ @namespace ||= 'NilClass' if nil_type?
72
+ @namespace ||= ((name == 'Class' or name == 'Module') and !subtypes.empty?) ? subtypes.first.name : name
73
+ end
74
+
75
+ # @return [Symbol] :class or :instance
76
+ def scope
77
+ @scope ||= :instance if duck_type? or nil_type?
78
+ @scope ||= ((name == 'Class' or name == 'Module') and !subtypes.empty?) ? :class : :instance
79
+ end
80
+
81
+ def == other
82
+ return false unless self.class == other.class
83
+ tag == other.tag
84
+ end
85
+
86
+ # Generate a ComplexType that fully qualifies this type's namespaces.
87
+ #
88
+ # @param api_map [ApiMap] The ApiMap that performs qualification
89
+ # @param context [String] The namespace from which to resolve names
90
+ # @return [ComplexType] The generated ComplexType
91
+ def qualify api_map, context = ''
92
+ return ComplexType.parse(tag) if duck_type? or void? or undefined?
93
+ fqns = api_map.qualify(name, context)
94
+ return ComplexType::UNDEFINED if fqns.nil?
95
+ ltypes = key_types.map do |t|
96
+ t.qualify api_map, context
97
+ end
98
+ rtypes = value_types.map do |t|
99
+ t.qualify api_map, context
100
+ end
101
+ if list_parameters?
102
+ Solargraph::ComplexType.parse("#{fqns}<#{rtypes.map(&:tag).join(', ')}>").first
103
+ elsif fixed_parameters?
104
+ Solargraph::ComplexType.parse("#{fqns}(#{rtypes.map(&:tag).join(', ')})").first
105
+ elsif hash_parameters?
106
+ Solargraph::ComplexType.parse("#{fqns}{#{ltypes.map(&:tag).join(', ')} => #{rtypes.map(&:tag).join(', ')}}").first
107
+ else
108
+ Solargraph::ComplexType.parse(fqns).first
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,35 @@
1
+ module Solargraph
2
+ class ComplexType
3
+ class UniqueType
4
+ include TypeMethods
5
+
6
+ # Create a BasicType with the specified name and an optional substring.
7
+ # The substring is the parameter section of a parametrized type, e.g., for
8
+ # the type `Array<String>`, the name is `Array` and the substring is
9
+ # `<String>`.
10
+ #
11
+ # @param name [String] The name of the type
12
+ # @param substring [String] The substring of the type
13
+ def initialize name, substring = ''
14
+ @name = name
15
+ @substring = substring
16
+ @tag = name + substring
17
+ @key_types = []
18
+ @subtypes = []
19
+ return unless parameters?
20
+ subs = ComplexType.parse(substring[1..-2], partial: true)
21
+ if hash_parameters?
22
+ raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(ComplexType) and !subs[1].is_a?(ComplexType)
23
+ @key_types.concat subs[0]
24
+ @subtypes.concat subs[1]
25
+ else
26
+ @subtypes.concat subs
27
+ end
28
+ end
29
+
30
+ def to_s
31
+ tag
32
+ end
33
+ end
34
+ end
35
+ end
@@ -12,6 +12,7 @@ module Solargraph
12
12
  Array#select Array#reject Array#keep_if Array#delete_if
13
13
  Enumerable#select
14
14
  Object#clone Object#dup Object#freeze Object#taint Object#untaint
15
+ String#freeze
15
16
  ].freeze
16
17
 
17
18
  METHODS_RETURNING_SUBTYPES = %w[
@@ -3,11 +3,12 @@ module Solargraph
3
3
  # and providing the results to language server clients.
4
4
  #
5
5
  module Diagnostics
6
- autoload :Base, 'solargraph/diagnostics/base'
7
- autoload :Severities, 'solargraph/diagnostics/severities'
8
- autoload :Rubocop, 'solargraph/diagnostics/rubocop'
6
+ autoload :Base, 'solargraph/diagnostics/base'
7
+ autoload :Severities, 'solargraph/diagnostics/severities'
8
+ autoload :Rubocop, 'solargraph/diagnostics/rubocop'
9
9
  autoload :RequireNotFound, 'solargraph/diagnostics/require_not_found'
10
- autoload :TypeNotDefined, 'solargraph/diagnostics/type_not_defined'
10
+ autoload :TypeNotDefined, 'solargraph/diagnostics/type_not_defined'
11
+ autoload :UpdateErrors, 'solargraph/diagnostics/update_errors'
11
12
 
12
13
  class << self
13
14
  # Add a reporter with a name to identify it in .solargraph.yml files.
@@ -44,5 +45,6 @@ module Solargraph
44
45
  register 'rubocop', Rubocop
45
46
  register 'require_not_found', RequireNotFound
46
47
  register 'type_not_defined', TypeNotDefined
48
+ register 'update_errors', UpdateErrors
47
49
  end
48
50
  end
@@ -5,10 +5,13 @@ module Solargraph
5
5
  # The result is an array of hash objects that conform to the LSP's
6
6
  # Diagnostic specification.
7
7
  #
8
+ # Subclasses should override this method.
9
+ #
8
10
  # @param source [Solargraph::Source]
9
11
  # @param api_map [Solargraph::ApiMap]
10
12
  # @return [Array<Hash>]
11
13
  def diagnose source, api_map
14
+ []
12
15
  end
13
16
  end
14
17
  end
@@ -7,7 +7,8 @@ module Solargraph
7
7
  def diagnose source, api_map
8
8
  result = []
9
9
  refs = {}
10
- source.requires.each do |ref|
10
+ map = Solargraph::SourceMap.map(source)
11
+ map.requires.each do |ref|
11
12
  refs[ref.name] = ref
12
13
  end
13
14
  api_map.unresolved_requires.each do |r|
@@ -20,7 +20,7 @@ module Solargraph
20
20
  # @return [Array<Hash>]
21
21
  def diagnose source, api_map
22
22
  begin
23
- options, paths = generate_options(api_map.workspace, source.filename, source.code)
23
+ options, paths = generate_options(source.filename, source.code)
24
24
  runner = RuboCop::Runner.new(options, RuboCop::ConfigStore.new)
25
25
  result = redirect_stdout{ runner.run(paths) }
26
26
  make_array JSON.parse(result)
@@ -35,18 +35,33 @@ module Solargraph
35
35
  # @param filename [String]
36
36
  # @param code [String]
37
37
  # @return [Array]
38
- def generate_options workspace, filename, code
38
+ # def generate_options workspace, filename, code
39
+ def generate_options filename, code
39
40
  args = ['-f', 'j']
40
- unless workspace.nil? or workspace.directory.nil?
41
- rc = File.join(workspace.directory, '.rubocop.yml')
42
- args.push('-c', fix_drive_letter(rc)) if File.file?(rc)
43
- end
41
+ rubocop_file = find_rubocop_file(filename)
42
+ args.push('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
44
43
  args.push filename
45
44
  options, paths = RuboCop::Options.new.parse(args)
46
45
  options[:stdin] = code
47
46
  [options, paths]
48
47
  end
49
48
 
49
+ def find_rubocop_file filename
50
+ rcfile = nil
51
+ dir = File.dirname(filename)
52
+ while rcfile.nil?
53
+ here = File.join(dir, '.rubocop.yml')
54
+ if File.exist?(here)
55
+ rcfile = here
56
+ break
57
+ else
58
+ break if File.dirname(dir) == dir
59
+ dir = File.dirname(dir)
60
+ end
61
+ end
62
+ rcfile
63
+ end
64
+
50
65
  # @todo This is a smelly way to redirect output, but the RuboCop specs do the
51
66
  # same thing.
52
67
  # @return [String]