solargraph 0.47.2 → 0.50.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/rspec.yml +1 -1
  4. data/CHANGELOG.md +40 -0
  5. data/LICENSE +1 -1
  6. data/README.md +9 -3
  7. data/SPONSORS.md +4 -4
  8. data/lib/solargraph/api_map/store.rb +13 -1
  9. data/lib/solargraph/api_map.rb +30 -12
  10. data/lib/solargraph/cache.rb +53 -0
  11. data/lib/solargraph/complex_type/type_methods.rb +10 -6
  12. data/lib/solargraph/complex_type/unique_type.rb +57 -0
  13. data/lib/solargraph/complex_type.rb +32 -3
  14. data/lib/solargraph/convention/rakefile.rb +17 -0
  15. data/lib/solargraph/convention.rb +2 -0
  16. data/lib/solargraph/diagnostics/rubocop.rb +17 -3
  17. data/lib/solargraph/diagnostics/rubocop_helpers.rb +3 -1
  18. data/lib/solargraph/language_server/host/cataloger.rb +1 -1
  19. data/lib/solargraph/language_server/host.rb +22 -18
  20. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  21. data/lib/solargraph/language_server/message/initialize.rb +2 -0
  22. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -1
  23. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  24. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  25. data/lib/solargraph/library.rb +25 -20
  26. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +12 -2
  27. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +24 -3
  28. data/lib/solargraph/parser/rubyvm/class_methods.rb +6 -1
  29. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +13 -2
  30. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +20 -8
  31. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +14 -3
  32. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +14 -3
  33. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +4 -2
  34. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
  35. data/lib/solargraph/pin/base.rb +5 -2
  36. data/lib/solargraph/pin/base_variable.rb +1 -1
  37. data/lib/solargraph/pin/conversions.rb +2 -6
  38. data/lib/solargraph/pin/method.rb +100 -10
  39. data/lib/solargraph/pin/namespace.rb +4 -1
  40. data/lib/solargraph/pin/parameter.rb +8 -3
  41. data/lib/solargraph/pin/signature.rb +23 -0
  42. data/lib/solargraph/pin.rb +1 -0
  43. data/lib/solargraph/rbs_map/conversions.rb +394 -0
  44. data/lib/solargraph/rbs_map/core_fills.rb +61 -0
  45. data/lib/solargraph/rbs_map/core_map.rb +38 -0
  46. data/lib/solargraph/rbs_map/core_signs.rb +33 -0
  47. data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
  48. data/lib/solargraph/rbs_map.rb +73 -0
  49. data/lib/solargraph/shell.rb +50 -32
  50. data/lib/solargraph/source/chain/call.rb +35 -24
  51. data/lib/solargraph/source/chain.rb +22 -7
  52. data/lib/solargraph/source_map/clip.rb +5 -0
  53. data/lib/solargraph/source_map/mapper.rb +8 -4
  54. data/lib/solargraph/type_checker.rb +71 -65
  55. data/lib/solargraph/version.rb +1 -1
  56. data/lib/solargraph/views/environment.erb +2 -2
  57. data/lib/solargraph/workspace.rb +11 -14
  58. data/lib/solargraph/yard_map/mapper/to_method.rb +7 -4
  59. data/lib/solargraph/yard_map.rb +35 -194
  60. data/lib/solargraph.rb +2 -2
  61. data/solargraph.gemspec +11 -6
  62. metadata +46 -37
  63. data/.travis.yml +0 -19
  64. data/lib/solargraph/compat.rb +0 -37
  65. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  66. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  67. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  68. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  69. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  70. data/yardoc/2.2.2.tar.gz +0 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class RbsMap
5
+ # Ruby core pins
6
+ #
7
+ class CoreMap
8
+ include Conversions
9
+
10
+ def initialize
11
+ cache = Cache.load('core.ser')
12
+ if cache
13
+ pins.replace cache
14
+ else
15
+ loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: true))
16
+ environment = RBS::Environment.from_loader(loader).resolve_type_names
17
+ environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
18
+ pins.concat RbsMap::CoreFills::ALL
19
+ processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
20
+ pins.replace processed
21
+
22
+ Cache.save('core.ser', pins)
23
+ end
24
+ end
25
+
26
+ def method_def_to_sigs decl, pin
27
+ stubs = CoreSigns.sign(pin.path)
28
+ return super unless stubs
29
+ stubs.map do |stub|
30
+ Pin::Signature.new(
31
+ [],
32
+ ComplexType.try_parse(stub.return_type)
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ module Solargraph
2
+ class RbsMap
3
+ module CoreSigns
4
+ Override = Pin::Reference::Override
5
+
6
+ class Stub
7
+ attr_reader :parameters
8
+
9
+ attr_reader :return_type
10
+
11
+ def initialize parameters, return_type
12
+ @parameters = parameters
13
+ @return_type = return_type
14
+ end
15
+ end
16
+
17
+ SIGNATURE_MAP = {
18
+ 'Object#class' => [
19
+ Stub.new(
20
+ [],
21
+ 'Class<self>'
22
+ )
23
+ ]
24
+ }
25
+
26
+ # @param path [String]
27
+ # @return [Array<Stub>]
28
+ def self.sign path
29
+ SIGNATURE_MAP[path]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+ require 'set'
5
+
6
+ module Solargraph
7
+ class RbsMap
8
+ # Ruby stdlib pins
9
+ #
10
+ class StdlibMap < RbsMap
11
+ # @type [Hash{String => RbsMap}]
12
+ @stdlib_maps_hash = {}
13
+
14
+ # @param library [String]
15
+ def initialize library
16
+ cache = Cache.load('stdlib', "#{library}.ser")
17
+ if cache
18
+ pins.replace cache
19
+ else
20
+ super
21
+ Cache.save('stdlib', "#{library}.ser", pins)
22
+ end
23
+ end
24
+
25
+ # @param library [String]
26
+ # @return [StdlibMap]
27
+ def self.load library
28
+ @stdlib_maps_hash[library] ||= StdlibMap.new(library)
29
+ end
30
+
31
+ def repository
32
+ @repository ||= RBS::Repository.new
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+ require 'set'
5
+
6
+ module Solargraph
7
+ class RbsMap
8
+ autoload :Conversions, 'solargraph/rbs_map/conversions'
9
+ autoload :CoreMap, 'solargraph/rbs_map/core_map'
10
+ autoload :CoreFills, 'solargraph/rbs_map/core_fills'
11
+ autoload :CoreSigns, 'solargraph/rbs_map/core_signs'
12
+ autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
13
+
14
+ include Conversions
15
+
16
+ # @type [Hash{String => RbsMap}]
17
+ @@rbs_maps_hash = {}
18
+
19
+ attr_reader :library
20
+
21
+ # @param library [String]
22
+ def initialize library
23
+ @library = library
24
+ loader = RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
25
+ add_library loader, library
26
+ return unless resolved?
27
+ environment = RBS::Environment.from_loader(loader).resolve_type_names
28
+ environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
29
+ end
30
+
31
+ def path_pin path
32
+ pins.find { |p| p.path == path }
33
+ end
34
+
35
+ def path_pins path
36
+ pins.select { |p| p.path == path }
37
+ end
38
+
39
+ def resolved?
40
+ @resolved
41
+ end
42
+
43
+ # @param library [String]
44
+ # @return [RbsMap]
45
+ def self.load library
46
+ @@rbs_maps_hash[library] ||= RbsMap.new(library)
47
+ end
48
+
49
+ def repository
50
+ @repository ||= RBS::Repository.new(no_stdlib: true)
51
+ end
52
+
53
+ private
54
+
55
+ # @param loader [RBS::EnvironmentLoader]
56
+ # @param library [String]
57
+ # @return [Boolean] true if adding the library succeeded
58
+ def add_library loader, library
59
+ @resolved = if loader.has_library?(library: library, version: nil)
60
+ loader.add library: library
61
+ Solargraph.logger.info "#{short_name} successfully loaded library #{library}"
62
+ true
63
+ else
64
+ Solargraph.logger.info "#{short_name} failed to load library #{library}"
65
+ false
66
+ end
67
+ end
68
+
69
+ def short_name
70
+ self.class.name.split('::').last
71
+ end
72
+ end
73
+ end
@@ -71,43 +71,46 @@ module Solargraph
71
71
  STDOUT.puts "Configuration file initialized."
72
72
  end
73
73
 
74
- desc 'download-core [VERSION]', 'Download core documentation'
75
- def download_core version = nil
76
- ver = version || Solargraph::YardMap::CoreDocs.best_download
77
- if RUBY_VERSION != ver
78
- puts "Documentation for #{RUBY_VERSION} is not available. Reverting to closest match..."
79
- end
80
- puts "Downloading docs for #{ver}..."
81
- Solargraph::YardMap::CoreDocs.download ver
82
- # Clear cached documentation if it exists
83
- FileUtils.rm_rf Dir.glob(File.join(Solargraph::YardMap::CoreDocs.cache_dir, ver, '*.ser'))
84
- puts "Download complete."
85
- rescue ArgumentError => e
86
- STDERR.puts "ERROR: #{e.message}"
87
- STDERR.puts "Run `solargraph available-cores` for a list."
88
- exit 1
89
- end
90
-
91
- desc 'list-cores', 'List the local documentation versions'
74
+ desc 'download-core [VERSION]', 'Download core documentation [deprecated]', hide: true
75
+ long_desc %(
76
+ The `download-core` command is deprecated. Current versions of Solargraph
77
+ use RBS for core and stdlib documentation.
78
+ )
79
+ # @deprecated
80
+ def download_core _version = nil
81
+ puts 'The `download-core` command is deprecated.'
82
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
83
+ end
84
+
85
+ desc 'list-cores', 'List the local documentation versions [deprecated]', hide: true
86
+ long_desc %(
87
+ The `list-cores` command is deprecated. Current versions of Solargraph use
88
+ RBS for core and stdlib documentation.
89
+ )
90
+ # @deprecated
92
91
  def list_cores
93
- puts Solargraph::YardMap::CoreDocs.versions.join("\n")
92
+ puts 'The `list-cores` command is deprecated.'
93
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
94
94
  end
95
95
 
96
- desc 'available-cores', 'List available documentation versions'
96
+ desc 'available-cores', 'List available documentation versions [deprecated]', hide: true
97
+ long_desc %(
98
+ The `available-cores` command is deprecated. Current versions of Solargraph
99
+ use RBS for core and stdlib documentation.
100
+ )
101
+ # @deprecated
97
102
  def available_cores
98
- puts Solargraph::YardMap::CoreDocs.available.join("\n")
103
+ puts 'The `available-cores` command is deprecated.'
104
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
99
105
  end
100
106
 
101
107
  desc 'clear', 'Delete all cached documentation'
102
108
  long_desc %(
103
109
  This command will delete all core and gem documentation from the cache.
104
- You can also delete specific gem caches with the `uncache` command or
105
- update documentation for specific Ruby versions with the `download-core`
106
- command.
107
110
  )
108
111
  def clear
109
112
  puts "Deleting the cached documentation"
110
- Solargraph::YardMap::CoreDocs.clear
113
+ Solargraph::Cache.clear
111
114
  end
112
115
  map 'clear-cache' => :clear
113
116
  map 'clear-cores' => :clear
@@ -191,18 +194,33 @@ module Solargraph
191
194
  puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
192
195
  end
193
196
 
194
- desc 'bundle', 'Generate documentation for bundled gems'
197
+ desc 'list', 'List the files in the workspace and the total count'
198
+ option :count, type: :boolean, aliases: :c, desc: 'Display the file count only', default: false
199
+ option :directory, type: :string, aliases: :d, desc: 'The directory to read', default: '.'
200
+ def list
201
+ workspace = Solargraph::Workspace.new(options[:directory])
202
+ unless options[:count]
203
+ workspace.filenames.each { |f| puts f }
204
+ end
205
+ puts "#{workspace.filenames.length} files total."
206
+ end
207
+
208
+ desc 'bundle', 'Generate documentation for bundled gems [deprecated]', hide: true
209
+ long_desc %(
210
+ The `bundle` command is deprecated. Solargraph currently uses RBS instead.
211
+ )
195
212
  option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
196
213
  option :rebuild, type: :boolean, aliases: :r, desc: 'Rebuild existing documentation', default: false
197
214
  def bundle
198
- Documentor.new(options[:directory], rebuild: options[:rebuild], out: STDOUT).document
215
+ puts 'The `bundle` command is deprecated. Solargraph currently uses RBS instead.'
199
216
  end
200
217
 
201
- desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation'
202
- def rdoc gem, version = '>= 0'
203
- spec = Gem::Specification.find_by_name(gem, version)
204
- puts "Caching #{spec.name} #{spec.version} from RDoc"
205
- Solargraph::YardMap::RdocToYard.run(spec)
218
+ desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation [deprecated]', hide: true
219
+ long_desc %(
220
+ The `rdoc` command is deprecated. Solargraph currently uses RBS instead.
221
+ )
222
+ def rdoc _gem, _version = '>= 0'
223
+ puts 'The `rdoc` command is deprecated. Solargraph currently uses RBS instead.'
206
224
  end
207
225
 
208
226
  private
@@ -35,7 +35,10 @@ module Solargraph
35
35
  []
36
36
  end
37
37
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
38
- pins = api_map.get_method_stack(name_pin.binder.namespace, word, scope: name_pin.binder.scope)
38
+ # @param [ComplexType::UniqueType]
39
+ pins = name_pin.binder.each_unique_type.flat_map do |context|
40
+ api_map.get_method_stack(context.namespace, word, scope: context.scope)
41
+ end
39
42
  return [] if pins.empty?
40
43
  inferred_pins(pins, api_map, name_pin.context, locals)
41
44
  end
@@ -49,36 +52,32 @@ module Solargraph
49
52
  # @return [Array<Pin::Base>]
50
53
  def inferred_pins pins, api_map, context, locals
51
54
  result = pins.map do |p|
52
- overloads = p.docstring.tags(:overload)
55
+ next p unless p.is_a?(Pin::Method)
56
+ overloads = p.signatures
53
57
  # next p if overloads.empty?
54
58
  type = ComplexType::UNDEFINED
55
- # @param [YARD::Tags::OverloadTag]
56
59
  overloads.each do |ol|
57
- next unless arguments_match(arguments, ol.parameters)
58
- next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
60
+ next unless arguments_match(arguments, ol)
61
+ # next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
59
62
  match = true
60
63
  arguments.each_with_index do |arg, idx|
61
- achain = arguments[idx]
62
- next if achain.nil?
63
64
  param = ol.parameters[idx]
64
65
  if param.nil?
65
- match = false unless ol.parameters.last && ol.parameters.last.first.start_with?('*')
66
+ match = false unless ol.parameters.any?(&:restarg?)
66
67
  break
67
68
  end
68
- par = ol.tags(:param).select { |pp| pp.name == param.first }.first
69
- next if par.nil? || par.types.nil? || par.types.empty?
70
- atype = achain.infer(api_map, Pin::ProxyType.anonymous(context), locals)
71
- other = ComplexType.try_parse(*par.types)
69
+ atype = arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
72
70
  # @todo Weak type comparison
73
- unless atype.tag == other.tag || api_map.super_and_sub?(other.tag, atype.tag)
71
+ # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
72
+ unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name)
74
73
  match = false
75
74
  break
76
75
  end
77
76
  end
78
77
  if match
79
- type = extra_return_type(ol, context)
78
+ type = extra_return_type(p.docstring, context)
80
79
  break if type
81
- type = ComplexType.try_parse(*ol.tag(:return).types).self_to(context.to_s).qualify(api_map, context.namespace) if ol.has_tag?(:return) && ol.tag(:return).types && !ol.tag(:return).types.empty? && (type.nil? || type.undefined?)
80
+ type = with_params(ol.return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if ol.return_type.defined?
82
81
  type ||= ComplexType::UNDEFINED
83
82
  end
84
83
  break if type.defined?
@@ -107,9 +106,13 @@ module Solargraph
107
106
  p
108
107
  end
109
108
  result.map do |pin|
110
- next pin if pin.return_type.undefined?
111
- selfy = pin.return_type.self_to(context.tag)
112
- selfy == pin.return_type ? pin : pin.proxy(selfy)
109
+ if pin.path == 'Class#new' && context.tag != 'Class'
110
+ pin.proxy(ComplexType.try_parse(context.namespace))
111
+ else
112
+ next pin if pin.return_type.undefined?
113
+ selfy = pin.return_type.self_to(context.tag)
114
+ selfy == pin.return_type ? pin : pin.proxy(selfy)
115
+ end
113
116
  end
114
117
  end
115
118
 
@@ -180,14 +183,15 @@ module Solargraph
180
183
  end
181
184
 
182
185
  # @param arguments [Array<Chain>]
183
- # @param parameters [Array<String>]
186
+ # @param signature [Pin::Signature]
184
187
  # @return [Boolean]
185
- def arguments_match arguments, parameters
188
+ def arguments_match arguments, signature
189
+ parameters = signature.parameters
186
190
  argcount = arguments.length
187
- # argcount -= 1 if !arguments.empty? && arguments.last.links.first.word.start_with?('&')
188
191
  parcount = parameters.length
189
- parcount -= 1 if !parameters.empty? && parameters.last.first.start_with?('&')
190
- return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.first.start_with?('*'))
192
+ parcount -= 1 if !parameters.empty? && parameters.last.block?
193
+ return false if signature.block? && !with_block?
194
+ return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
191
195
  true
192
196
  end
193
197
 
@@ -195,9 +199,16 @@ module Solargraph
195
199
  # @param name_pin [Pin::Base]
196
200
  # @return [Array<Pin::Base>]
197
201
  def super_pins api_map, name_pin
198
- pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
202
+ pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
199
203
  pins.reject{|p| p.path == name_pin.path}
200
204
  end
205
+
206
+ # @param type [ComplexType]
207
+ # @param context [ComplexType]
208
+ def with_params type, context
209
+ return type unless type.to_s.include?('$')
210
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
211
+ end
201
212
  end
202
213
  end
203
214
  end
@@ -63,11 +63,11 @@ module Solargraph
63
63
  working_pin = name_pin
64
64
  links[0..-2].each do |link|
65
65
  pins = link.resolve(api_map, working_pin, locals)
66
- type = infer_first_defined(pins, working_pin, api_map)
66
+ type = infer_first_defined(pins, working_pin, api_map, locals)
67
67
  return [] if type.undefined?
68
68
  working_pin = Pin::ProxyType.anonymous(type)
69
69
  end
70
- links.last.last_context = working_pin
70
+ links.last.last_context = name_pin
71
71
  links.last.resolve(api_map, working_pin, locals)
72
72
  end
73
73
 
@@ -76,8 +76,12 @@ module Solargraph
76
76
  # @param locals [Array<Pin::Base>]
77
77
  # @return [ComplexType]
78
78
  def infer api_map, name_pin, locals
79
+ from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
80
+ if from_here
81
+ name_pin = name_pin.proxy(from_here)
82
+ end
79
83
  pins = define(api_map, name_pin, locals)
80
- type = infer_first_defined(pins, links.last.last_context, api_map)
84
+ type = infer_first_defined(pins, links.last.last_context, api_map, locals)
81
85
  maybe_nil(type)
82
86
  end
83
87
 
@@ -110,9 +114,10 @@ module Solargraph
110
114
  private
111
115
 
112
116
  # @param pins [Array<Pin::Base>]
117
+ # @param context [Pin::Base]
113
118
  # @param api_map [ApiMap]
114
119
  # @return [ComplexType]
115
- def infer_first_defined pins, context, api_map
120
+ def infer_first_defined pins, context, api_map, locals
116
121
  possibles = []
117
122
  pins.each do |pin|
118
123
  # Avoid infinite recursion
@@ -121,8 +126,18 @@ module Solargraph
121
126
  type = pin.typify(api_map)
122
127
  @@inference_stack.pop
123
128
  if type.defined?
124
- possibles.push type
125
- break if pin.is_a?(Pin::Method)
129
+ if type.parameterized?
130
+ type = type.resolve_parameters(pin.closure, context)
131
+ # idx = pin.closure.parameters.index(type.subtypes.first.name)
132
+ # next if idx.nil?
133
+ # param_type = context.return_type.all_params[idx]
134
+ # next unless param_type
135
+ # type = ComplexType.try_parse(param_type.to_s)
136
+ end
137
+ if type.defined?
138
+ possibles.push type
139
+ break if pin.is_a?(Pin::Method)
140
+ end
126
141
  end
127
142
  end
128
143
  if possibles.empty?
@@ -147,7 +162,7 @@ module Solargraph
147
162
  sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
148
163
  ComplexType.parse(*sorted)
149
164
  else
150
- possibles.first
165
+ ComplexType.parse(possibles.map(&:to_s).join(', '))
151
166
  end
152
167
  return type if context.nil? || context.return_type.undefined?
153
168
  type.self_to(context.return_type.namespace)
@@ -43,6 +43,11 @@ module Solargraph
43
43
  # @return [ComplexType]
44
44
  def infer
45
45
  result = cursor.chain.infer(api_map, block, locals)
46
+ if result.tag == 'Class'
47
+ # HACK: Exception to return Object from Class#new
48
+ dfn = cursor.chain.define(api_map, block, locals).first
49
+ return ComplexType.try_parse('Object') if dfn && dfn.path == 'Class#new'
50
+ end
46
51
  return result unless result.tag == 'self'
47
52
  ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).namespace)
48
53
  end
@@ -12,7 +12,7 @@ module Solargraph
12
12
 
13
13
  private_class_method :new
14
14
 
15
- MACRO_REGEXP = /(@\!method|@\!attribute|@\!visibility|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
15
+ DIRECTIVE_REGEXP = /(@\!method|@\!attribute|@\!visibility|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
16
16
 
17
17
  # Generate the data.
18
18
  #
@@ -24,6 +24,8 @@ module Solargraph
24
24
  @code = source.code
25
25
  @comments = source.comments
26
26
  @pins, @locals = Parser.map(source)
27
+ @pins.each { |p| p.source = :code }
28
+ @locals.each { |l| l.source = :code }
27
29
  process_comment_directives
28
30
  [@pins, @locals]
29
31
  # rescue Exception => e
@@ -63,7 +65,7 @@ module Solargraph
63
65
  end
64
66
 
65
67
  def process_comment source_position, comment_position, comment
66
- return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ MACRO_REGEXP
68
+ return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
67
69
  cmnt = remove_inline_comment_hashes(comment)
68
70
  parse = Solargraph::Source.parse_docstring(cmnt)
69
71
  last_line = 0
@@ -196,6 +198,8 @@ module Solargraph
196
198
  namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
197
199
  when 'override'
198
200
  pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags)
201
+ when 'macro'
202
+ # @todo Handle macros
199
203
  end
200
204
  end
201
205
 
@@ -209,7 +213,7 @@ module Solargraph
209
213
  started = false
210
214
  comment.lines.each { |l|
211
215
  # Trim the comment and minimum leading whitespace
212
- p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#/, '')
216
+ p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '')
213
217
  if num.nil? && !p.strip.empty?
214
218
  num = p.index(/[^ ]/)
215
219
  started = true
@@ -224,7 +228,7 @@ module Solargraph
224
228
 
225
229
  # @return [void]
226
230
  def process_comment_directives
227
- return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ MACRO_REGEXP
231
+ return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
228
232
  code_lines = @code.lines
229
233
  @source.associated_comments.each do |line, comments|
230
234
  src_pos = line ? Position.new(line, code_lines[line].to_s.chomp.index(/[^\s]/) || 0) : Position.new(code_lines.length, 0)