solargraph 0.56.0 → 0.57.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +148 -6
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +5 -2
  6. data/.gitignore +5 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +2627 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +56 -1
  13. data/README.md +8 -4
  14. data/Rakefile +125 -13
  15. data/lib/solargraph/api_map/cache.rb +3 -2
  16. data/lib/solargraph/api_map/constants.rb +218 -0
  17. data/lib/solargraph/api_map/index.rb +20 -26
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +126 -18
  20. data/lib/solargraph/api_map.rb +212 -234
  21. data/lib/solargraph/bench.rb +1 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +1 -0
  23. data/lib/solargraph/complex_type/unique_type.rb +7 -7
  24. data/lib/solargraph/complex_type.rb +5 -1
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +17 -0
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  29. data/lib/solargraph/convention/data_definition.rb +105 -0
  30. data/lib/solargraph/convention/gemspec.rb +3 -2
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -2
  33. data/lib/solargraph/convention/struct_definition.rb +87 -24
  34. data/lib/solargraph/convention.rb +32 -2
  35. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  36. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  37. data/lib/solargraph/doc_map.rb +48 -17
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +17 -11
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +3 -0
  42. data/lib/solargraph/language_server/host.rb +2 -1
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
  45. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  46. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  48. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  49. data/lib/solargraph/language_server/progress.rb +8 -0
  50. data/lib/solargraph/language_server/request.rb +1 -0
  51. data/lib/solargraph/library.rb +47 -30
  52. data/lib/solargraph/location.rb +2 -0
  53. data/lib/solargraph/logging.rb +11 -2
  54. data/lib/solargraph/page.rb +4 -0
  55. data/lib/solargraph/parser/comment_ripper.rb +8 -1
  56. data/lib/solargraph/parser/flow_sensitive_typing.rb +32 -4
  57. data/lib/solargraph/parser/node_methods.rb +2 -2
  58. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  59. data/lib/solargraph/parser/node_processor.rb +24 -8
  60. data/lib/solargraph/parser/parser_gem/class_methods.rb +1 -1
  61. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  62. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
  63. data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
  64. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
  65. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +1 -21
  66. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  68. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +0 -22
  69. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +1 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  71. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +1 -0
  72. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +35 -14
  73. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +1 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  75. data/lib/solargraph/parser/region.rb +3 -0
  76. data/lib/solargraph/parser/snippet.rb +2 -0
  77. data/lib/solargraph/pin/base.rb +65 -8
  78. data/lib/solargraph/pin/base_variable.rb +1 -2
  79. data/lib/solargraph/pin/callable.rb +9 -0
  80. data/lib/solargraph/pin/closure.rb +2 -0
  81. data/lib/solargraph/pin/common.rb +6 -2
  82. data/lib/solargraph/pin/constant.rb +2 -0
  83. data/lib/solargraph/pin/delegated_method.rb +1 -0
  84. data/lib/solargraph/pin/local_variable.rb +4 -1
  85. data/lib/solargraph/pin/method.rb +12 -7
  86. data/lib/solargraph/pin/method_alias.rb +3 -0
  87. data/lib/solargraph/pin/parameter.rb +18 -8
  88. data/lib/solargraph/pin/proxy_type.rb +1 -0
  89. data/lib/solargraph/pin/reference/override.rb +15 -1
  90. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  91. data/lib/solargraph/pin/reference.rb +26 -0
  92. data/lib/solargraph/pin/search.rb +3 -1
  93. data/lib/solargraph/pin/signature.rb +2 -0
  94. data/lib/solargraph/pin/symbol.rb +5 -0
  95. data/lib/solargraph/pin_cache.rb +64 -4
  96. data/lib/solargraph/position.rb +2 -0
  97. data/lib/solargraph/range.rb +1 -0
  98. data/lib/solargraph/rbs_map/conversions.rb +47 -18
  99. data/lib/solargraph/rbs_map/core_map.rb +3 -0
  100. data/lib/solargraph/rbs_map.rb +15 -2
  101. data/lib/solargraph/shell.rb +3 -0
  102. data/lib/solargraph/source/chain/link.rb +10 -1
  103. data/lib/solargraph/source/chain.rb +9 -2
  104. data/lib/solargraph/source/change.rb +2 -2
  105. data/lib/solargraph/source/cursor.rb +2 -3
  106. data/lib/solargraph/source/source_chainer.rb +1 -1
  107. data/lib/solargraph/source.rb +5 -2
  108. data/lib/solargraph/source_map/clip.rb +1 -1
  109. data/lib/solargraph/source_map/data.rb +4 -0
  110. data/lib/solargraph/source_map/mapper.rb +4 -2
  111. data/lib/solargraph/source_map.rb +21 -14
  112. data/lib/solargraph/type_checker/param_def.rb +2 -0
  113. data/lib/solargraph/type_checker/rules.rb +8 -0
  114. data/lib/solargraph/type_checker.rb +173 -120
  115. data/lib/solargraph/version.rb +1 -1
  116. data/lib/solargraph/workspace/config.rb +1 -3
  117. data/lib/solargraph/workspace/require_paths.rb +98 -0
  118. data/lib/solargraph/workspace.rb +24 -48
  119. data/lib/solargraph/yard_map/helpers.rb +29 -1
  120. data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -5
  121. data/lib/solargraph/yard_map/mapper/to_method.rb +3 -8
  122. data/lib/solargraph/yard_map/mapper/to_namespace.rb +7 -7
  123. data/lib/solargraph/yardoc.rb +18 -3
  124. data/lib/solargraph.rb +15 -0
  125. data/rbs/fills/tuple.rbs +2 -3
  126. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  127. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  128. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  129. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  130. data/solargraph.gemspec +14 -4
  131. metadata +128 -11
  132. data/lib/.rubocop.yml +0 -22
@@ -8,8 +8,9 @@ module Solargraph
8
8
 
9
9
  module NodeProcessors
10
10
  class StructNode < Parser::NodeProcessor::Base
11
+ # @return [Boolean] continue processing the next processor of the same node.
11
12
  def process
12
- return if struct_definition_node.nil?
13
+ return true if struct_definition_node.nil?
13
14
 
14
15
  loc = get_node_location(node)
15
16
  nspin = Solargraph::Pin::Namespace.new(
@@ -17,9 +18,10 @@ module Solargraph
17
18
  location: loc,
18
19
  closure: region.closure,
19
20
  name: struct_definition_node.class_name,
20
- comments: comments_for(node),
21
+ docstring: docstring,
21
22
  visibility: :public,
22
- gates: region.closure.gates.freeze
23
+ gates: region.closure.gates.freeze,
24
+ source: :struct_definition
23
25
  )
24
26
  pins.push nspin
25
27
 
@@ -31,7 +33,8 @@ module Solargraph
31
33
  location: get_node_location(node),
32
34
  closure: nspin,
33
35
  visibility: :private,
34
- comments: comments_for(node)
36
+ docstring: docstring,
37
+ source: :struct_definition
35
38
  )
36
39
 
37
40
  pins.push initialize_method_pin
@@ -42,7 +45,8 @@ module Solargraph
42
45
  name: attribute_name,
43
46
  decl: struct_definition_node.keyword_init? ? :kwarg : :arg,
44
47
  location: get_node_location(attribute_node),
45
- closure: initialize_method_pin
48
+ closure: initialize_method_pin,
49
+ source: :struct_definition
46
50
  )
47
51
  )
48
52
  end
@@ -50,49 +54,108 @@ module Solargraph
50
54
  # define attribute accessors and instance variables
51
55
  struct_definition_node.attributes.each do |attribute_node, attribute_name|
52
56
  [attribute_name, "#{attribute_name}="].each do |name|
57
+ docs = docstring.tags.find { |t| t.tag_name == 'param' && t.name == attribute_name }
58
+
59
+ attribute_type = ComplexType.parse(tag_string(docs))
60
+ return_type_comment = attribute_comment(docs, false)
61
+ param_comment = attribute_comment(docs, true)
62
+
53
63
  method_pin = Pin::Method.new(
54
64
  name: name,
55
65
  parameters: [],
56
66
  scope: :instance,
57
67
  location: get_node_location(attribute_node),
58
68
  closure: nspin,
59
- comments: attribute_comments(attribute_node, attribute_name),
60
- visibility: :public
69
+ docstring: YARD::Docstring.new(return_type_comment),
70
+ # even assignments return the value
71
+ comments: return_type_comment,
72
+ return_type: attribute_type,
73
+ visibility: :public,
74
+ source: :struct_definition
61
75
  )
62
76
 
63
- pins.push method_pin
77
+ if name.end_with?('=')
78
+ method_pin.parameters << Pin::Parameter.new(
79
+ name: attribute_name,
80
+ location: get_node_location(attribute_node),
81
+ closure: method_pin,
82
+ return_type: attribute_type,
83
+ comments: param_comment,
84
+ source: :struct_definition
85
+ )
64
86
 
65
- next unless name.include?('=') # setter
66
- pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
67
- closure: method_pin,
68
- location: get_node_location(attribute_node),
69
- comments: attribute_comments(attribute_node, attribute_name))
87
+ pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
88
+ closure: method_pin,
89
+ location: get_node_location(attribute_node),
90
+ return_type: attribute_type,
91
+ comments: "@type [#{attribute_type.rooted_tags}]",
92
+ source: :struct_definition)
93
+ end
94
+
95
+ pins.push method_pin
70
96
  end
71
97
  end
72
98
 
73
99
  process_children region.update(closure: nspin, visibility: :public)
100
+ false
74
101
  end
75
102
 
76
103
  private
77
104
 
78
- # @return [StructDefintionNode, nil]
105
+ # @return [StructDefintionNode, StructAssignmentNode, nil]
79
106
  def struct_definition_node
80
- @struct_definition_node ||= if StructDefintionNode.valid?(node)
107
+ @struct_definition_node ||= if StructDefintionNode.match?(node)
81
108
  StructDefintionNode.new(node)
82
- elsif StructAssignmentNode.valid?(node)
109
+ elsif StructAssignmentNode.match?(node)
83
110
  StructAssignmentNode.new(node)
84
111
  end
85
112
  end
86
113
 
87
- # @param attribute_node [Parser::AST::Node]
88
- # @return [String, nil]
89
- def attribute_comments(attribute_node, attribute_name)
90
- struct_comments = comments_for(attribute_node)
91
- return if struct_comments.nil? || struct_comments.empty?
114
+ # Gets/generates the relevant docstring for this struct & it's attributes
115
+ # @return [YARD::Docstring]
116
+ def docstring
117
+ @docstring ||= parse_comments
118
+ end
119
+
120
+ # Parses any relevant comments for a struct int a yard docstring
121
+ # @return [YARD::Docstring]
122
+ def parse_comments
123
+ struct_comments = comments_for(node) || ''
124
+ struct_definition_node.attributes.each do |attr_node, attr_name|
125
+ comment = comments_for(attr_node)
126
+ next if comment.nil?
92
127
 
93
- struct_comments.split("\n").find do |row|
94
- row.include?(attribute_name)
95
- end&.gsub('@param', '@return')&.gsub(attribute_name, '')
128
+ # We should support specific comments for an attribute, and that can be either a @return on an @param
129
+ # But since we merge into the struct_comments, then we should interpret either as a param
130
+ comment = "@param #{attr_name}#{comment[7..]}" if comment.start_with?('@return')
131
+
132
+ struct_comments += "\n#{comment}"
133
+ end
134
+
135
+ Solargraph::Source.parse_docstring(struct_comments).to_docstring
136
+ end
137
+
138
+ # @param tag [YARD::Tags::Tag, nil] The param tag for this attribute.xtract_
139
+ #
140
+ # @return [String]
141
+ def tag_string(tag)
142
+ tag&.types&.join(',') || 'undefined'
143
+ end
144
+
145
+ # @param tag [YARD::Tags::Tag, nil] The param tag for this attribute. If nil, this method is a no-op
146
+ # @param for_setter [Boolean] If true, will return a @param tag instead of a @return tag
147
+ #
148
+ # @return [String] The formatted comment for the attribute
149
+ def attribute_comment(tag, for_setter)
150
+ return "" if tag.nil?
151
+
152
+ suffix = "[#{tag_string(tag)}] #{tag.text}"
153
+
154
+ if for_setter
155
+ "@param #{tag.name} #{suffix}"
156
+ else
157
+ "@return #{suffix}"
158
+ end
96
159
  end
97
160
  end
98
161
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Solargraph
5
4
  # Conventions provide a way to modify an ApiMap based on expectations about
6
5
  # one of its sources.
@@ -11,6 +10,8 @@ module Solargraph
11
10
  autoload :Gemspec, 'solargraph/convention/gemspec'
12
11
  autoload :Rakefile, 'solargraph/convention/rakefile'
13
12
  autoload :StructDefinition, 'solargraph/convention/struct_definition'
13
+ autoload :DataDefinition, 'solargraph/convention/data_definition'
14
+ autoload :ActiveSupportConcern, 'solargraph/convention/active_support_concern'
14
15
 
15
16
  # @type [Set<Convention::Base>]
16
17
  @@conventions = Set.new
@@ -21,6 +22,12 @@ module Solargraph
21
22
  @@conventions.add convention.new
22
23
  end
23
24
 
25
+ # @param convention [Class<Convention::Base>]
26
+ # @return [void]
27
+ def self.unregister convention
28
+ @@conventions.delete_if { |c| c.is_a?(convention) }
29
+ end
30
+
24
31
  # @param source_map [SourceMap]
25
32
  # @return [Environ]
26
33
  def self.for_local(source_map)
@@ -31,7 +38,7 @@ module Solargraph
31
38
  result
32
39
  end
33
40
 
34
- # @param yard_map [DocMap]
41
+ # @param doc_map [DocMap]
35
42
  # @return [Environ]
36
43
  def self.for_global(doc_map)
37
44
  result = Environ.new
@@ -41,8 +48,31 @@ module Solargraph
41
48
  result
42
49
  end
43
50
 
51
+ # Provides any additional method pins based on the described object.
52
+ #
53
+ # @param api_map [ApiMap]
54
+ # @param rooted_tag [String] A fully qualified namespace, with
55
+ # generic parameter values if applicable
56
+ # @param scope [Symbol] :class or :instance
57
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
58
+ # @param deep [Boolean]
59
+ # @param skip [Set<String>]
60
+ # @param no_core [Boolean] Skip core classes if true
61
+ #
62
+ # @return [Environ]
63
+ def self.for_object api_map, rooted_tag, scope, visibility,
64
+ deep, skip, no_core
65
+ result = Environ.new
66
+ @@conventions.each do |conv|
67
+ result.merge conv.object(api_map, rooted_tag, scope, visibility,
68
+ deep, skip, no_core)
69
+ end
70
+ result
71
+ end
72
+
44
73
  register Gemfile
45
74
  register Gemspec
46
75
  register Rakefile
76
+ register ActiveSupportConcern
47
77
  end
48
78
  end
@@ -28,7 +28,12 @@ module Solargraph
28
28
  options, paths = generate_options(source.filename, source.code)
29
29
  store = RuboCop::ConfigStore.new
30
30
  runner = RuboCop::Runner.new(options, store)
31
- result = redirect_stdout{ runner.run(paths) }
31
+ # Ensure only one instance of RuboCop::Runner is running at
32
+ # a time - it uses 'chdir' to read config files with ERB,
33
+ # which can conflict with other chdirs.
34
+ result = Solargraph::CHDIR_MUTEX.synchronize do
35
+ redirect_stdout{ runner.run(paths) }
36
+ end
32
37
 
33
38
  return [] if result.empty?
34
39
 
@@ -15,10 +15,10 @@ module Solargraph
15
15
  # @return [void]
16
16
  def require_rubocop(version = nil)
17
17
  begin
18
+ # @type [String]
18
19
  gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
19
20
  gem_lib_path = File.join(gem_path, 'lib')
20
21
  $LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
21
- # @todo Gem::MissingSpecVersionError is undocumented for some reason
22
22
  # @sg-ignore
23
23
  rescue Gem::MissingSpecVersionError => e
24
24
  raise InvalidRubocopVersionError,
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'benchmark'
5
+ require 'open3'
5
6
 
6
7
  module Solargraph
7
8
  # A collection of pins generated from required gems.
@@ -21,8 +22,9 @@ module Solargraph
21
22
 
22
23
  # @return [Array<Gem::Specification>]
23
24
  def uncached_gemspecs
24
- (uncached_yard_gemspecs + uncached_rbs_collection_gemspecs).sort.
25
- uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
25
+ uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs)
26
+ .sort
27
+ .uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
26
28
  end
27
29
 
28
30
  # @return [Array<Gem::Specification>]
@@ -31,8 +33,10 @@ module Solargraph
31
33
  # @return [Array<Gem::Specification>]
32
34
  attr_reader :uncached_rbs_collection_gemspecs
33
35
 
36
+ # @return [String, nil]
34
37
  attr_reader :rbs_collection_path
35
38
 
39
+ # @return [String, nil]
36
40
  attr_reader :rbs_collection_config_path
37
41
 
38
42
  # @return [Workspace, nil]
@@ -51,10 +55,13 @@ module Solargraph
51
55
  @rbs_collection_path = workspace&.rbs_collection_path
52
56
  @rbs_collection_config_path = workspace&.rbs_collection_config_path
53
57
  @environ = Convention.for_global(self)
58
+ @requires.concat @environ.requires if @environ
54
59
  load_serialized_gem_pins
55
60
  pins.concat @environ.pins
56
61
  end
57
62
 
63
+ # @param out [IO]
64
+ # @return [void]
58
65
  def cache_all!(out)
59
66
  # if we log at debug level:
60
67
  if logger.info?
@@ -72,12 +79,18 @@ module Solargraph
72
79
  @uncached_yard_gemspecs = []
73
80
  end
74
81
 
82
+ # @param gemspec [Gem::Specification]
83
+ # @param out [IO]
84
+ # @return [void]
75
85
  def cache_yard_pins(gemspec, out)
76
- pins = GemPins.build_yard_pins(gemspec)
86
+ pins = GemPins.build_yard_pins(yard_plugins, gemspec)
77
87
  PinCache.serialize_yard_gem(gemspec, pins)
78
88
  logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
79
89
  end
80
90
 
91
+ # @param gemspec [Gem::Specification]
92
+ # @param out [IO]
93
+ # @return [void]
81
94
  def cache_rbs_collection_pins(gemspec, out)
82
95
  rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
83
96
  pins = rbs_map.pins
@@ -89,6 +102,9 @@ module Solargraph
89
102
  end
90
103
 
91
104
  # @param gemspec [Gem::Specification]
105
+ # @param rebuild [Boolean] whether to rebuild the pins even if they are cached
106
+ # @param out [IO, nil] output stream for logging
107
+ # @return [void]
92
108
  def cache(gemspec, rebuild: false, out: nil)
93
109
  build_yard = uncached_yard_gemspecs.include?(gemspec) || rebuild
94
110
  build_rbs_collection = uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
@@ -112,30 +128,42 @@ module Solargraph
112
128
  @unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
113
129
  end
114
130
 
131
+ # @return [Hash{Array(String, String) => Array<Gem::Specification>}] Indexed by gemspec name and version
115
132
  def self.all_yard_gems_in_memory
116
133
  @yard_gems_in_memory ||= {}
117
134
  end
118
135
 
136
+ # @return [Hash{String => Hash{Array(String, String) => Array<Pin::Base>}}] stored by RBS collection path
119
137
  def self.all_rbs_collection_gems_in_memory
120
138
  @rbs_collection_gems_in_memory ||= {}
121
139
  end
122
140
 
141
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
123
142
  def yard_pins_in_memory
124
143
  self.class.all_yard_gems_in_memory
125
144
  end
126
145
 
146
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
127
147
  def rbs_collection_pins_in_memory
128
148
  self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
129
149
  end
130
150
 
151
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
131
152
  def self.all_combined_pins_in_memory
132
153
  @combined_pins_in_memory ||= {}
133
154
  end
134
155
 
156
+ # @todo this should also include an index by the hash of the RBS collection
157
+ # @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
135
158
  def combined_pins_in_memory
136
159
  self.class.all_combined_pins_in_memory
137
160
  end
138
161
 
162
+ # @return [Array<String>]
163
+ def yard_plugins
164
+ @environ.yard_plugins
165
+ end
166
+
139
167
  # @return [Set<Gem::Specification>]
140
168
  def dependencies
141
169
  @dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
@@ -149,7 +177,11 @@ module Solargraph
149
177
  @uncached_yard_gemspecs = []
150
178
  @uncached_rbs_collection_gemspecs = []
151
179
  with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
180
+ # @sg-ignore Wrong argument type for Hash.[]: arg_0 expected _ToHash<Array(String, Array<Gem::Specification>), undefined>, received Array<Array(String, Array<Gem::Specification>)>
181
+ # @type [Array<String>]
152
182
  paths = Hash[without_gemspecs].keys
183
+ # @sg-ignore Wrong argument type for Hash.[]: arg_0 expected _ToHash<Array(String, Array<Gem::Specification>), undefined>, received Array<Array(String, Array<Gem::Specification>)>
184
+ # @type [Array<Gem::Specification>]
153
185
  gemspecs = Hash[with_gemspecs].values.flatten.compact + dependencies.to_a
154
186
 
155
187
  paths.each do |path|
@@ -258,6 +290,8 @@ module Solargraph
258
290
  end
259
291
  end
260
292
 
293
+ # @param gemspec [Gem::Specification]
294
+ # @param rbs_version_cache_key [String]
261
295
  # @return [Array<Pin::Base>, nil]
262
296
  def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
263
297
  return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
@@ -273,22 +307,13 @@ module Solargraph
273
307
  end
274
308
  end
275
309
 
276
- # @param gemspec [Gem::Specification]
277
- # @return [Boolean]
278
- def try_gem_in_memory gemspec
279
- gempins = DocMap.gems_in_memory[gemspec]
280
- return false unless gempins
281
- Solargraph.logger.debug "Found #{gemspec.name} #{gemspec.version} in memory"
282
- @pins.concat gempins
283
- true
284
- end
285
-
286
310
  # @param path [String]
287
311
  # @return [::Array<Gem::Specification>, nil]
288
312
  def resolve_path_to_gemspecs path
289
313
  return nil if path.empty?
290
314
  return gemspecs_required_from_bundler if path == 'bundler/require'
291
315
 
316
+ # @type [Gem::Specification, nil]
292
317
  gemspec = Gem::Specification.find_by_path(path)
293
318
  if gemspec.nil?
294
319
  gem_name_guess = path.split('/').first
@@ -312,10 +337,12 @@ module Solargraph
312
337
  # @param gemspec [Gem::Specification]
313
338
  # @return [Gem::Specification]
314
339
  def gemspec_or_preference gemspec
340
+ # :nocov: dormant feature
315
341
  return gemspec unless preference_map.key?(gemspec.name)
316
342
  return gemspec if gemspec.version == preference_map[gemspec.name].version
317
343
 
318
- change_gemspec_version gemspec, preference_map[by_path.name].version
344
+ change_gemspec_version gemspec, preference_map[gemspec.name].version
345
+ # :nocov:
319
346
  end
320
347
 
321
348
  # @param gemspec [Gem::Specification]
@@ -354,8 +381,12 @@ module Solargraph
354
381
  self.class.inspect
355
382
  end
356
383
 
384
+ # @return [Array<Gem::Specification>]
357
385
  def gemspecs_required_from_bundler
358
- if workspace&.directory && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory)
386
+ # @todo Handle projects with custom Bundler/Gemfile setups
387
+ return unless workspace.gemfile?
388
+
389
+ if workspace.gemfile? && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory)
359
390
  # Find only the gems bundler is now using
360
391
  Bundler.definition.locked_gems.specs.flat_map do |lazy_spec|
361
392
  logger.info "Handling #{lazy_spec.name}:#{lazy_spec.version}"
@@ -373,6 +404,7 @@ module Solargraph
373
404
  end
374
405
  end
375
406
 
407
+ # @return [Array<Gem::Specification>]
376
408
  def gemspecs_required_from_external_bundle
377
409
  logger.info 'Fetching gemspecs required from external bundle'
378
410
  return [] unless workspace&.directory
@@ -396,8 +428,7 @@ module Solargraph
396
428
  next specs
397
429
  end.compact
398
430
  else
399
- Solargraph.logger.warn e
400
- raise BundleNotFoundError, "Failed to load gems from bundle at #{workspace&.directory}"
431
+ Solargraph.logger.warn "Failed to load gems from bundle at #{workspace&.directory}: #{e}"
401
432
  end
402
433
  end
403
434
  end
@@ -13,16 +13,21 @@ module Solargraph
13
13
  # @return [Array<String>]
14
14
  attr_reader :domains
15
15
 
16
- # @return [Array<Pin::Reference::Override>]
16
+ # @return [Array<Pin::Base>]
17
17
  attr_reader :pins
18
18
 
19
+ # @return [Array<String>]
20
+ attr_reader :yard_plugins
21
+
19
22
  # @param requires [Array<String>]
20
23
  # @param domains [Array<String>]
21
24
  # @param pins [Array<Pin::Base>]
22
- def initialize requires: [], domains: [], pins: []
25
+ # @param yard_plugins[Array<String>]
26
+ def initialize requires: [], domains: [], pins: [], yard_plugins: []
23
27
  @requires = requires
24
28
  @domains = domains
25
29
  @pins = pins
30
+ @yard_plugins = yard_plugins
26
31
  end
27
32
 
28
33
  # @return [self]
@@ -30,6 +35,7 @@ module Solargraph
30
35
  domains.clear
31
36
  requires.clear
32
37
  pins.clear
38
+ yard_plugins.clear
33
39
  self
34
40
  end
35
41
 
@@ -39,6 +45,7 @@ module Solargraph
39
45
  domains.concat other.domains
40
46
  requires.concat other.requires
41
47
  pins.concat other.pins
48
+ yard_plugins.concat other.yard_plugins
42
49
  self
43
50
  end
44
51
  end
@@ -11,17 +11,9 @@ module Solargraph
11
11
  include Logging
12
12
  end
13
13
 
14
- # @param gemspec [Gem::Specification]
15
- # @return [Array<Pin::Base>]
16
- def self.build_yard_pins(gemspec)
17
- Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
18
- yardoc = Yardoc.load!(gemspec)
19
- YardMap::Mapper.new(yardoc, gemspec).map
20
- end
21
-
22
14
  # @param pins [Array<Pin::Base>]
15
+ # @return [Array<Pin::Base>]
23
16
  def self.combine_method_pins_by_path(pins)
24
- # bad_pins = pins.select { |pin| pin.is_a?(Pin::Method) && pin.path == 'StringIO.open' && pin.source == :rbs }; raise "wtf: #{bad_pins}" if bad_pins.length > 1
25
17
  method_pins, alias_pins = pins.partition { |pin| pin.class == Pin::Method }
26
18
  by_path = method_pins.group_by(&:path)
27
19
  by_path.transform_values! do |pins|
@@ -30,8 +22,12 @@ module Solargraph
30
22
  by_path.values + alias_pins
31
23
  end
32
24
 
25
+ # @param pins [Array<Pin::Method>]
26
+ # @return [Pin::Method, nil]
33
27
  def self.combine_method_pins(*pins)
34
- out = pins.reduce(nil) do |memo, pin|
28
+ # @type [Pin::Method, nil]
29
+ combined_pin = nil
30
+ out = pins.reduce(combined_pin) do |memo, pin|
35
31
  next pin if memo.nil?
36
32
  if memo == pin && memo.source != :combined
37
33
  # @todo we should track down situations where we are handled
@@ -45,8 +41,18 @@ module Solargraph
45
41
  out
46
42
  end
47
43
 
44
+ # @param yard_plugins [Array<String>] The names of YARD plugins to use.
45
+ # @param gemspec [Gem::Specification]
46
+ # @return [Array<Pin::Base>]
47
+ def self.build_yard_pins(yard_plugins, gemspec)
48
+ Yardoc.cache(yard_plugins, gemspec) unless Yardoc.cached?(gemspec)
49
+ yardoc = Yardoc.load!(gemspec)
50
+ YardMap::Mapper.new(yardoc, gemspec).map
51
+ end
52
+
48
53
  # @param yard_pins [Array<Pin::Base>]
49
- # @param rbs_map [RbsMap]
54
+ # @param rbs_pins [Array<Pin::Base>]
55
+ #
50
56
  # @return [Array<Pin::Base>]
51
57
  def self.combine(yard_pins, rbs_pins)
52
58
  in_yard = Set.new
@@ -95,6 +95,7 @@ module Solargraph
95
95
  nil
96
96
  end
97
97
 
98
+ # @return [Hash{String => undefined}]
98
99
  def options
99
100
  @options ||= {}.freeze
100
101
  end
@@ -118,6 +119,7 @@ module Solargraph
118
119
  end
119
120
 
120
121
  # @param library [Solargraph::Library]
122
+ # @param progress [Solargraph::LanguageServer::Progress, nil]
121
123
  # @return [void]
122
124
  def update progress
123
125
  progress&.send(self)
@@ -72,10 +72,12 @@ module Solargraph
72
72
 
73
73
  private
74
74
 
75
+ # @return [Hash, nil]
75
76
  def next_message
76
77
  cancel_message || next_priority
77
78
  end
78
79
 
80
+ # @return [Hash, nil]
79
81
  def cancel_message
80
82
  # Handle cancellations first
81
83
  idx = messages.find_index { |msg| msg['method'] == '$/cancelRequest' }
@@ -86,6 +88,7 @@ module Solargraph
86
88
  msg
87
89
  end
88
90
 
91
+ # @return [Hash, nil]
89
92
  def next_priority
90
93
  # Prioritize updates and version-dependent messages for performance
91
94
  idx = messages.find_index do |msg|
@@ -299,6 +299,7 @@ module Solargraph
299
299
  end
300
300
  end
301
301
 
302
+ # @return [String]
302
303
  def command_path
303
304
  options['commandPath'] || 'solargraph'
304
305
  end
@@ -716,7 +717,7 @@ module Solargraph
716
717
  # A hash of client requests by ID. The host uses this to keep track of
717
718
  # pending responses.
718
719
  #
719
- # @return [Hash{Integer => Solargraph::LanguageServer::Host}]
720
+ # @return [Hash{Integer => Solargraph::LanguageServer::Request}]
720
721
  def requests
721
722
  @requests ||= {}
722
723
  end
@@ -16,7 +16,7 @@ module Solargraph
16
16
  # @return [String]
17
17
  attr_reader :method
18
18
 
19
- # @return [Hash{String => Array<undefined>, Hash{String => undefined}, String, Integer}]
19
+ # @return [Hash{String => undefined}]
20
20
  attr_reader :params
21
21
 
22
22
  # @return [Hash, Array, nil]
@@ -79,6 +79,7 @@ module Solargraph
79
79
 
80
80
  private
81
81
 
82
+ # @return [void]
82
83
  def accept_or_cancel
83
84
  if host.cancel?(id)
84
85
  # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
@@ -83,7 +83,7 @@ module Solargraph
83
83
  @fetched = true
84
84
  begin
85
85
  @available ||= begin
86
- # @sg-ignore
86
+ # @sg-ignore Variable type could not be inferred for tuple
87
87
  # @type [Gem::Dependency, nil]
88
88
  tuple = CheckGemVersion.fetcher.search_for_dependency(Gem::Dependency.new('solargraph')).flatten.first
89
89
  if tuple.nil?
@@ -10,6 +10,7 @@ module Solargraph::LanguageServer::Message::TextDocument
10
10
 
11
11
  private
12
12
 
13
+ # @return [Array<Hash>]
13
14
  def code_location
14
15
  suggestions = host.definitions_at(params['textDocument']['uri'], @line, @column)
15
16
  return nil if suggestions.empty?
@@ -21,6 +22,7 @@ module Solargraph::LanguageServer::Message::TextDocument
21
22
  end
22
23
  end
23
24
 
25
+ # @return [Array<Hash>]
24
26
  def require_location
25
27
  # @todo Terrible hack
26
28
  lib = host.library_for(params['textDocument']['uri'])