solargraph 0.54.4 → 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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +149 -5
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -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 +104 -0
  13. data/README.md +20 -6
  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 +44 -42
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +165 -32
  20. data/lib/solargraph/api_map.rb +319 -243
  21. data/lib/solargraph/bench.rb +18 -1
  22. data/lib/solargraph/complex_type/type_methods.rb +7 -1
  23. data/lib/solargraph/complex_type/unique_type.rb +105 -16
  24. data/lib/solargraph/complex_type.rb +40 -7
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +20 -3
  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 +61 -0
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  33. data/lib/solargraph/convention/struct_definition.rb +164 -0
  34. data/lib/solargraph/convention.rb +35 -4
  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 +313 -65
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +60 -38
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +13 -7
  42. data/lib/solargraph/language_server/host.rb +14 -3
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  45. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  46. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  47. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  49. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  50. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  51. data/lib/solargraph/language_server/progress.rb +8 -0
  52. data/lib/solargraph/language_server/request.rb +1 -0
  53. data/lib/solargraph/library.rb +53 -32
  54. data/lib/solargraph/location.rb +23 -0
  55. data/lib/solargraph/logging.rb +12 -2
  56. data/lib/solargraph/page.rb +4 -0
  57. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  58. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  59. data/lib/solargraph/parser/node_methods.rb +16 -2
  60. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  61. data/lib/solargraph/parser/node_processor.rb +26 -9
  62. data/lib/solargraph/parser/parser_gem/class_methods.rb +17 -15
  63. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  64. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +8 -4
  66. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  68. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  70. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  73. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  74. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  75. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  76. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  80. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
  81. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  83. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  84. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +63 -30
  85. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  86. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  89. data/lib/solargraph/parser/region.rb +4 -1
  90. data/lib/solargraph/parser/snippet.rb +2 -0
  91. data/lib/solargraph/parser.rb +1 -0
  92. data/lib/solargraph/pin/base.rb +360 -30
  93. data/lib/solargraph/pin/base_variable.rb +16 -10
  94. data/lib/solargraph/pin/block.rb +2 -0
  95. data/lib/solargraph/pin/breakable.rb +9 -0
  96. data/lib/solargraph/pin/callable.rb +83 -3
  97. data/lib/solargraph/pin/closure.rb +20 -1
  98. data/lib/solargraph/pin/common.rb +10 -1
  99. data/lib/solargraph/pin/constant.rb +2 -0
  100. data/lib/solargraph/pin/delegated_method.rb +21 -1
  101. data/lib/solargraph/pin/documenting.rb +16 -0
  102. data/lib/solargraph/pin/keyword.rb +7 -2
  103. data/lib/solargraph/pin/local_variable.rb +18 -6
  104. data/lib/solargraph/pin/method.rb +175 -46
  105. data/lib/solargraph/pin/method_alias.rb +3 -0
  106. data/lib/solargraph/pin/namespace.rb +17 -9
  107. data/lib/solargraph/pin/parameter.rb +78 -19
  108. data/lib/solargraph/pin/proxy_type.rb +13 -6
  109. data/lib/solargraph/pin/reference/override.rb +24 -6
  110. data/lib/solargraph/pin/reference/require.rb +2 -2
  111. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  112. data/lib/solargraph/pin/reference.rb +26 -0
  113. data/lib/solargraph/pin/search.rb +3 -1
  114. data/lib/solargraph/pin/signature.rb +44 -0
  115. data/lib/solargraph/pin/singleton.rb +1 -1
  116. data/lib/solargraph/pin/symbol.rb +8 -2
  117. data/lib/solargraph/pin/until.rb +18 -0
  118. data/lib/solargraph/pin/while.rb +18 -0
  119. data/lib/solargraph/pin.rb +4 -1
  120. data/lib/solargraph/pin_cache.rb +245 -0
  121. data/lib/solargraph/position.rb +11 -0
  122. data/lib/solargraph/range.rb +10 -0
  123. data/lib/solargraph/rbs_map/conversions.rb +226 -70
  124. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  125. data/lib/solargraph/rbs_map/core_map.rb +37 -11
  126. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  127. data/lib/solargraph/rbs_map.rb +88 -18
  128. data/lib/solargraph/shell.rb +20 -18
  129. data/lib/solargraph/source/chain/array.rb +11 -7
  130. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  131. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  132. data/lib/solargraph/source/chain/call.rb +53 -23
  133. data/lib/solargraph/source/chain/constant.rb +1 -1
  134. data/lib/solargraph/source/chain/hash.rb +4 -3
  135. data/lib/solargraph/source/chain/head.rb +1 -1
  136. data/lib/solargraph/source/chain/if.rb +1 -1
  137. data/lib/solargraph/source/chain/link.rb +12 -1
  138. data/lib/solargraph/source/chain/literal.rb +22 -2
  139. data/lib/solargraph/source/chain/or.rb +1 -1
  140. data/lib/solargraph/source/chain/z_super.rb +1 -1
  141. data/lib/solargraph/source/chain.rb +84 -47
  142. data/lib/solargraph/source/change.rb +2 -2
  143. data/lib/solargraph/source/cursor.rb +2 -3
  144. data/lib/solargraph/source/source_chainer.rb +3 -3
  145. data/lib/solargraph/source.rb +5 -2
  146. data/lib/solargraph/source_map/clip.rb +4 -2
  147. data/lib/solargraph/source_map/data.rb +4 -0
  148. data/lib/solargraph/source_map/mapper.rb +13 -7
  149. data/lib/solargraph/source_map.rb +21 -31
  150. data/lib/solargraph/type_checker/checks.rb +4 -0
  151. data/lib/solargraph/type_checker/param_def.rb +2 -0
  152. data/lib/solargraph/type_checker/rules.rb +8 -0
  153. data/lib/solargraph/type_checker.rb +208 -128
  154. data/lib/solargraph/version.rb +1 -1
  155. data/lib/solargraph/views/_method.erb +10 -10
  156. data/lib/solargraph/views/_namespace.erb +3 -3
  157. data/lib/solargraph/views/document.erb +10 -10
  158. data/lib/solargraph/workspace/config.rb +1 -3
  159. data/lib/solargraph/workspace/require_paths.rb +98 -0
  160. data/lib/solargraph/workspace.rb +38 -52
  161. data/lib/solargraph/yard_map/helpers.rb +29 -1
  162. data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
  163. data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
  164. data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
  165. data/lib/solargraph/yard_map/mapper.rb +4 -3
  166. data/lib/solargraph/yard_map/to_method.rb +4 -2
  167. data/lib/solargraph/yardoc.rb +22 -10
  168. data/lib/solargraph.rb +34 -1
  169. data/rbs/fills/tuple.rbs +149 -0
  170. data/rbs_collection.yaml +19 -0
  171. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  172. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  173. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  174. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  175. data/solargraph.gemspec +15 -4
  176. metadata +157 -15
  177. data/lib/.rubocop.yml +0 -22
  178. data/lib/solargraph/cache.rb +0 -77
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ autoload :DataDefintionNode, 'solargraph/convention/data_definition/data_definition_node'
7
+ autoload :DataAssignmentNode, 'solargraph/convention/data_definition/data_assignment_node'
8
+
9
+ module NodeProcessors
10
+ class DataNode < Parser::NodeProcessor::Base
11
+ # @return [Boolean] continue processing the next processor of the same node.
12
+ def process
13
+ return true if data_definition_node.nil?
14
+
15
+ loc = get_node_location(node)
16
+ nspin = Solargraph::Pin::Namespace.new(
17
+ type: :class,
18
+ location: loc,
19
+ closure: region.closure,
20
+ name: data_definition_node.class_name,
21
+ comments: comments_for(node),
22
+ visibility: :public,
23
+ gates: region.closure.gates.freeze
24
+ )
25
+ pins.push nspin
26
+
27
+ # define initialize method
28
+ initialize_method_pin = Pin::Method.new(
29
+ name: 'initialize',
30
+ parameters: [],
31
+ scope: :instance,
32
+ location: get_node_location(node),
33
+ closure: nspin,
34
+ visibility: :private,
35
+ comments: comments_for(node)
36
+ )
37
+
38
+ # @todo Support both arg and kwarg initializers for Data.define
39
+ # Solargraph::SourceMap::Clip#complete_keyword_parameters does not seem to currently take into account [Pin::Method#signatures] hence we only one for :kwarg
40
+ pins.push initialize_method_pin
41
+
42
+ data_definition_node.attributes.map do |attribute_node, attribute_name|
43
+ initialize_method_pin.parameters.push(
44
+ Pin::Parameter.new(
45
+ name: attribute_name,
46
+ decl: :kwarg,
47
+ location: get_node_location(attribute_node),
48
+ closure: initialize_method_pin
49
+ )
50
+ )
51
+ end
52
+
53
+ # define attribute readers and instance variables
54
+ data_definition_node.attributes.each do |attribute_node, attribute_name|
55
+ name = attribute_name.to_s
56
+ method_pin = Pin::Method.new(
57
+ name: name,
58
+ parameters: [],
59
+ scope: :instance,
60
+ location: get_node_location(attribute_node),
61
+ closure: nspin,
62
+ comments: attribute_comments(attribute_node, attribute_name),
63
+ visibility: :public
64
+ )
65
+
66
+ pins.push method_pin
67
+
68
+ pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
69
+ closure: method_pin,
70
+ location: get_node_location(attribute_node),
71
+ comments: attribute_comments(attribute_node, attribute_name))
72
+ end
73
+
74
+ process_children region.update(closure: nspin, visibility: :public)
75
+
76
+ false
77
+ end
78
+
79
+ private
80
+
81
+ # @return [DataDefintionNode, nil]
82
+ def data_definition_node
83
+ @data_definition_node ||= if DataDefintionNode.match?(node)
84
+ DataDefintionNode.new(node)
85
+ elsif DataAssignmentNode.match?(node)
86
+ DataAssignmentNode.new(node)
87
+ end
88
+ end
89
+
90
+ # @param attribute_node [Parser::AST::Node]
91
+ # @param attribute_name [String]
92
+ # @return [String, nil]
93
+ def attribute_comments(attribute_node, attribute_name)
94
+ data_comments = comments_for(attribute_node)
95
+ return if data_comments.nil? || data_comments.empty?
96
+
97
+ data_comments.split("\n").find do |row|
98
+ row.include?(attribute_name)
99
+ end&.gsub('@param', '@return')&.gsub(attribute_name, '')
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -4,7 +4,7 @@ module Solargraph
4
4
  module Convention
5
5
  class Gemspec < Base
6
6
  def local source_map
7
- return EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
7
+ return Convention::Base::EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
8
8
  @environ ||= Environ.new(
9
9
  requires: ['rubygems'],
10
10
  pins: [
@@ -12,7 +12,8 @@ module Solargraph
12
12
  'Gem::Specification.new',
13
13
  %(
14
14
  @yieldparam [self]
15
- )
15
+ ),
16
+ source: :gemspec
16
17
  )
17
18
  ]
18
19
  )
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module StructDefinition
6
+ # A node wrapper for a Struct definition via const assignment.
7
+ # @example
8
+ # MyStruct = Struct.new(:bar, :baz) do
9
+ # def foo
10
+ # end
11
+ # end
12
+ class StructAssignmentNode < StructDefintionNode
13
+ class << self
14
+ # @example
15
+ # s(:casgn, nil, :Foo,
16
+ # s(:block,
17
+ # s(:send,
18
+ # s(:const, nil, :Struct), :new,
19
+ # s(:sym, :bar),
20
+ # s(:sym, :baz)),
21
+ # s(:args),
22
+ # s(:def, :foo,
23
+ # s(:args),
24
+ # s(:send, nil, :bar))))
25
+ # @param node [Parser::AST::Node]
26
+ def match?(node)
27
+ return false unless node&.type == :casgn
28
+ return false if node.children[2].nil?
29
+
30
+ struct_node = if node.children[2].type == :block
31
+ node.children[2].children[0]
32
+ else
33
+ node.children[2]
34
+ end
35
+
36
+ struct_definition_node?(struct_node)
37
+ end
38
+ end
39
+
40
+ def class_name
41
+ if node.children[0]
42
+ Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
43
+ else
44
+ node.children[1].to_s
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # @return [Parser::AST::Node]
51
+ def struct_node
52
+ if node.children[2].type == :block
53
+ node.children[2].children[0]
54
+ else
55
+ node.children[2]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module StructDefinition
6
+ # A node wrapper for a Struct definition via inheritance.
7
+ # @example
8
+ # class MyStruct < Struct.new(:bar, :baz)
9
+ # def foo
10
+ # end
11
+ # end
12
+ class StructDefintionNode
13
+ class << self
14
+ # @example
15
+ # s(:class,
16
+ # s(:const, nil, :Foo),
17
+ # s(:send,
18
+ # s(:const, nil, :Struct), :new,
19
+ # s(:sym, :bar),
20
+ # s(:sym, :baz)),
21
+ # s(:hash,
22
+ # s(:pair,
23
+ # s(:sym, :keyword_init),
24
+ # s(:true)))),
25
+ # s(:def, :foo,
26
+ # s(:args),
27
+ # s(:send, nil, :bar)))
28
+ #
29
+ # @param node [Parser::AST::Node]
30
+ def match?(node)
31
+ return false unless node&.type == :class
32
+
33
+ struct_definition_node?(node.children[1])
34
+ end
35
+
36
+ private
37
+
38
+ # @param struct_node [Parser::AST::Node]
39
+ # @return [Boolean]
40
+ def struct_definition_node?(struct_node)
41
+ return false unless struct_node.is_a?(::Parser::AST::Node)
42
+ return false unless struct_node&.type == :send
43
+ return false unless struct_node.children[0]&.type == :const
44
+ return false unless struct_node.children[0].children[1] == :Struct
45
+ return false unless struct_node.children[1] == :new
46
+
47
+ true
48
+ end
49
+ end
50
+
51
+ # @param node [Parser::AST::Node]
52
+ def initialize(node)
53
+ @node = node
54
+ end
55
+
56
+ # @return [String]
57
+ def class_name
58
+ Parser::NodeMethods.unpack_name(node)
59
+ end
60
+
61
+ # @return [Array<Array(Parser::AST::Node, String)>]
62
+ def attributes
63
+ struct_attribute_nodes.map do |struct_def_param|
64
+ next unless struct_def_param.type == :sym
65
+ [struct_def_param, struct_def_param.children[0].to_s]
66
+ end.compact
67
+ end
68
+
69
+ def keyword_init?
70
+ keyword_init_param = struct_attribute_nodes.find do |struct_def_param|
71
+ struct_def_param.type == :hash && struct_def_param.children[0].type == :pair &&
72
+ struct_def_param.children[0].children[0].children[0] == :keyword_init
73
+ end
74
+
75
+ return false if keyword_init_param.nil?
76
+
77
+ keyword_init_param.children[0].children[1].type == :true
78
+ end
79
+
80
+ # @return [Parser::AST::Node]
81
+ def body_node
82
+ node.children[2]
83
+ end
84
+
85
+ private
86
+
87
+ # @return [Parser::AST::Node]
88
+ attr_reader :node
89
+
90
+ # @return [Parser::AST::Node]
91
+ def struct_node
92
+ node.children[1]
93
+ end
94
+
95
+ # @return [Array<Parser::AST::Node>]
96
+ def struct_attribute_nodes
97
+ struct_node.children[2..-1]
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module StructDefinition
6
+ autoload :StructDefintionNode, 'solargraph/convention/struct_definition/struct_definition_node'
7
+ autoload :StructAssignmentNode, 'solargraph/convention/struct_definition/struct_assignment_node'
8
+
9
+ module NodeProcessors
10
+ class StructNode < Parser::NodeProcessor::Base
11
+ # @return [Boolean] continue processing the next processor of the same node.
12
+ def process
13
+ return true if struct_definition_node.nil?
14
+
15
+ loc = get_node_location(node)
16
+ nspin = Solargraph::Pin::Namespace.new(
17
+ type: :class,
18
+ location: loc,
19
+ closure: region.closure,
20
+ name: struct_definition_node.class_name,
21
+ docstring: docstring,
22
+ visibility: :public,
23
+ gates: region.closure.gates.freeze,
24
+ source: :struct_definition
25
+ )
26
+ pins.push nspin
27
+
28
+ # define initialize method
29
+ initialize_method_pin = Pin::Method.new(
30
+ name: 'initialize',
31
+ parameters: [],
32
+ scope: :instance,
33
+ location: get_node_location(node),
34
+ closure: nspin,
35
+ visibility: :private,
36
+ docstring: docstring,
37
+ source: :struct_definition
38
+ )
39
+
40
+ pins.push initialize_method_pin
41
+
42
+ struct_definition_node.attributes.map do |attribute_node, attribute_name|
43
+ initialize_method_pin.parameters.push(
44
+ Pin::Parameter.new(
45
+ name: attribute_name,
46
+ decl: struct_definition_node.keyword_init? ? :kwarg : :arg,
47
+ location: get_node_location(attribute_node),
48
+ closure: initialize_method_pin,
49
+ source: :struct_definition
50
+ )
51
+ )
52
+ end
53
+
54
+ # define attribute accessors and instance variables
55
+ struct_definition_node.attributes.each do |attribute_node, attribute_name|
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
+
63
+ method_pin = Pin::Method.new(
64
+ name: name,
65
+ parameters: [],
66
+ scope: :instance,
67
+ location: get_node_location(attribute_node),
68
+ closure: nspin,
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
75
+ )
76
+
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
+ )
86
+
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
96
+ end
97
+ end
98
+
99
+ process_children region.update(closure: nspin, visibility: :public)
100
+ false
101
+ end
102
+
103
+ private
104
+
105
+ # @return [StructDefintionNode, StructAssignmentNode, nil]
106
+ def struct_definition_node
107
+ @struct_definition_node ||= if StructDefintionNode.match?(node)
108
+ StructDefintionNode.new(node)
109
+ elsif StructAssignmentNode.match?(node)
110
+ StructAssignmentNode.new(node)
111
+ end
112
+ end
113
+
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?
127
+
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
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ 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.
@@ -10,6 +9,9 @@ module Solargraph
10
9
  autoload :Gemfile, 'solargraph/convention/gemfile'
11
10
  autoload :Gemspec, 'solargraph/convention/gemspec'
12
11
  autoload :Rakefile, 'solargraph/convention/rakefile'
12
+ autoload :StructDefinition, 'solargraph/convention/struct_definition'
13
+ autoload :DataDefinition, 'solargraph/convention/data_definition'
14
+ autoload :ActiveSupportConcern, 'solargraph/convention/active_support_concern'
13
15
 
14
16
  # @type [Set<Convention::Base>]
15
17
  @@conventions = Set.new
@@ -20,6 +22,12 @@ module Solargraph
20
22
  @@conventions.add convention.new
21
23
  end
22
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
+
23
31
  # @param source_map [SourceMap]
24
32
  # @return [Environ]
25
33
  def self.for_local(source_map)
@@ -30,12 +38,34 @@ module Solargraph
30
38
  result
31
39
  end
32
40
 
33
- # @param yard_map [YardMap]
41
+ # @param doc_map [DocMap]
42
+ # @return [Environ]
43
+ def self.for_global(doc_map)
44
+ result = Environ.new
45
+ @@conventions.each do |conv|
46
+ result.merge conv.global(doc_map)
47
+ end
48
+ result
49
+ end
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
+ #
34
62
  # @return [Environ]
35
- def self.for_global(yard_map)
63
+ def self.for_object api_map, rooted_tag, scope, visibility,
64
+ deep, skip, no_core
36
65
  result = Environ.new
37
66
  @@conventions.each do |conv|
38
- result.merge conv.global(yard_map)
67
+ result.merge conv.object(api_map, rooted_tag, scope, visibility,
68
+ deep, skip, no_core)
39
69
  end
40
70
  result
41
71
  end
@@ -43,5 +73,6 @@ module Solargraph
43
73
  register Gemfile
44
74
  register Gemspec
45
75
  register Rakefile
76
+ register ActiveSupportConcern
46
77
  end
47
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,