Skip to content

Commit 2e6e327

Browse files
authored
[regression] Fix crash while typechecking files with Struct use (#1031)
* [regression] Fix crash while typechecking files with Struct use It looks like a mis-set closure field on a Parameter in is causing exceptions while typechecking code with Struct use inside: https://github.com/iftheshoefritz/solargraph-rails/actions/runs/17040847020/job/48303963447?pr=158 * Set types in parameters and instance variables * Fix specs * Fix linting issues * Rebaseline .rubocop_todo.yml * Rebaseline .rubocop_todo.yml
1 parent 02acc4c commit 2e6e327

File tree

3 files changed

+75
-40
lines changed

3 files changed

+75
-40
lines changed

.rubocop_todo.yml

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ Gemspec/RequiredRubyVersion:
5757
# SupportedStyles: with_first_argument, with_fixed_indentation
5858
Layout/ArgumentAlignment:
5959
Exclude:
60-
- 'lib/solargraph/convention/struct_definition.rb'
6160
- 'lib/solargraph/pin/callable.rb'
6261
- 'spec/source/source_chainer_spec.rb'
6362

@@ -117,14 +116,12 @@ Layout/EmptyLines:
117116
Exclude:
118117
- 'lib/solargraph/bench.rb'
119118
- 'lib/solargraph/complex_type/unique_type.rb'
120-
- 'lib/solargraph/convention.rb'
121119
- 'lib/solargraph/doc_map.rb'
122120
- 'lib/solargraph/language_server/message/extended/check_gem_version.rb'
123121
- 'lib/solargraph/language_server/message/initialize.rb'
124122
- 'lib/solargraph/pin/delegated_method.rb'
125123
- 'lib/solargraph/rbs_map/conversions.rb'
126124
- 'spec/complex_type_spec.rb'
127-
- 'spec/convention/struct_definition_spec.rb'
128125
- 'spec/pin/local_variable_spec.rb'
129126
- 'spec/pin/symbol_spec.rb'
130127
- 'spec/type_checker/levels/strict_spec.rb'
@@ -233,7 +230,6 @@ Layout/FirstHashElementIndentation:
233230
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
234231
Layout/HashAlignment:
235232
Exclude:
236-
- 'lib/solargraph/convention/struct_definition.rb'
237233
- 'lib/solargraph/workspace/config.rb'
238234

239235
# This cop supports safe autocorrection (--autocorrect).
@@ -265,6 +261,7 @@ Layout/IndentationWidth:
265261
- 'lib/solargraph/type_checker/rules.rb'
266262
- 'lib/solargraph/yard_map/mapper.rb'
267263
- 'spec/api_map/config_spec.rb'
264+
- 'spec/shell_spec.rb'
268265
- 'spec/source_map/mapper_spec.rb'
269266

270267
# This cop supports safe autocorrection (--autocorrect).
@@ -444,20 +441,12 @@ Layout/SpaceInsideParens:
444441
- 'lib/solargraph/pin/namespace.rb'
445442
- 'lib/solargraph/source_map.rb'
446443

447-
# This cop supports safe autocorrection (--autocorrect).
448-
# Configuration parameters: EnforcedStyle.
449-
# SupportedStyles: final_newline, final_blank_line
450-
Layout/TrailingEmptyLines:
451-
Exclude:
452-
- 'spec/convention/struct_definition_spec.rb'
453-
454444
# This cop supports safe autocorrection (--autocorrect).
455445
# Configuration parameters: AllowInHeredoc.
456446
Layout/TrailingWhitespace:
457447
Exclude:
458448
- 'lib/solargraph/language_server/message/client/register_capability.rb'
459449
- 'spec/api_map/config_spec.rb'
460-
- 'spec/convention/struct_definition_spec.rb'
461450
- 'spec/convention_spec.rb'
462451

463452
# This cop supports safe autocorrection (--autocorrect).
@@ -532,7 +521,6 @@ Lint/DuplicateMethods:
532521
- 'lib/solargraph/complex_type.rb'
533522
- 'lib/solargraph/location.rb'
534523
- 'lib/solargraph/pin/base.rb'
535-
- 'lib/solargraph/pin/common.rb'
536524
- 'lib/solargraph/pin/signature.rb'
537525
- 'lib/solargraph/rbs_map.rb'
538526
- 'lib/solargraph/rbs_map/core_map.rb'
@@ -674,6 +662,7 @@ Lint/UnusedMethodArgument:
674662
- 'lib/solargraph/source/chain/literal.rb'
675663
- 'lib/solargraph/source/chain/variable.rb'
676664
- 'lib/solargraph/source/chain/z_super.rb'
665+
- 'spec/doc_map_spec.rb'
677666

678667
# This cop supports safe autocorrection (--autocorrect).
679668
# Configuration parameters: AutoCorrect, ContextCreatingMethods, MethodCreatingMethods.
@@ -747,6 +736,7 @@ Metrics/BlockLength:
747736
- 'lib/solargraph/api_map.rb'
748737
- 'lib/solargraph/api_map/source_to_yard.rb'
749738
- 'lib/solargraph/complex_type.rb'
739+
- 'lib/solargraph/convention/struct_definition.rb'
750740
- 'lib/solargraph/parser/parser_gem/node_processors/send_node.rb'
751741
- 'lib/solargraph/source/chain/call.rb'
752742
- 'lib/solargraph/type_checker.rb'
@@ -809,7 +799,6 @@ Metrics/ParameterLists:
809799
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
810800
Metrics/PerceivedComplexity:
811801
Exclude:
812-
- 'lib/solargraph/api_map/source_to_yard.rb'
813802
- 'lib/solargraph/complex_type.rb'
814803
- 'lib/solargraph/parser/parser_gem/node_chainer.rb'
815804
- 'lib/solargraph/source/chain/call.rb'
@@ -866,7 +855,6 @@ Naming/PredicateMethod:
866855
- 'lib/solargraph/api_map/store.rb'
867856
- 'lib/solargraph/convention/data_definition.rb'
868857
- 'lib/solargraph/convention/struct_definition.rb'
869-
- 'lib/solargraph/doc_map.rb'
870858
- 'lib/solargraph/language_server/progress.rb'
871859
- 'lib/solargraph/library.rb'
872860
- 'lib/solargraph/parser/node_processor/base.rb'
@@ -907,11 +895,6 @@ RSpec/BeEq:
907895
- 'spec/complex_type_spec.rb'
908896
- 'spec/pin/method_spec.rb'
909897

910-
# This cop supports unsafe autocorrection (--autocorrect-all).
911-
RSpec/BeEql:
912-
Exclude:
913-
- 'spec/convention/struct_definition_spec.rb'
914-
915898
# This cop supports safe autocorrection (--autocorrect).
916899
# Configuration parameters: EnforcedStyle.
917900
# SupportedStyles: be, be_nil
@@ -1190,6 +1173,7 @@ RSpec/MultipleExpectations:
11901173
- 'spec/rbs_map/core_map_spec.rb'
11911174
- 'spec/rbs_map/stdlib_map_spec.rb'
11921175
- 'spec/rbs_map_spec.rb'
1176+
- 'spec/shell_spec.rb'
11931177
- 'spec/source/chain/call_spec.rb'
11941178
- 'spec/source/chain/class_variable_spec.rb'
11951179
- 'spec/source/chain/global_variable_spec.rb'
@@ -1306,6 +1290,7 @@ RSpec/SpecFilePathFormat:
13061290
- 'spec/api_map/source_to_yard_spec.rb'
13071291
- 'spec/api_map/store_spec.rb'
13081292
- 'spec/api_map_spec.rb'
1293+
- 'spec/convention/activesupport_concern_spec.rb'
13091294
- 'spec/convention/struct_definition_spec.rb'
13101295
- 'spec/convention_spec.rb'
13111296
- 'spec/diagnostics/base_spec.rb'
@@ -1360,6 +1345,7 @@ RSpec/SpecFilePathFormat:
13601345
- 'spec/rbs_map/core_map_spec.rb'
13611346
- 'spec/rbs_map/stdlib_map_spec.rb'
13621347
- 'spec/rbs_map_spec.rb'
1348+
- 'spec/shell_spec.rb'
13631349
- 'spec/source/chain/array_spec.rb'
13641350
- 'spec/source/chain/call_spec.rb'
13651351
- 'spec/source/chain/class_variable_spec.rb'
@@ -1440,7 +1426,6 @@ Style/AccessModifierDeclarations:
14401426
# SupportedStyles: separated, grouped
14411427
Style/AccessorGrouping:
14421428
Exclude:
1443-
- 'lib/solargraph/doc_map.rb'
14441429
- 'lib/solargraph/parser/flow_sensitive_typing.rb'
14451430
- 'lib/solargraph/pin/base.rb'
14461431
- 'lib/solargraph/pin/method.rb'
@@ -1866,6 +1851,7 @@ Style/FrozenStringLiteralComment:
18661851
- 'spec/rbs_map/core_map_spec.rb'
18671852
- 'spec/rbs_map/stdlib_map_spec.rb'
18681853
- 'spec/rbs_map_spec.rb'
1854+
- 'spec/shell_spec.rb'
18691855
- 'spec/source/chain/array_spec.rb'
18701856
- 'spec/source/chain/call_spec.rb'
18711857
- 'spec/source/chain/class_variable_spec.rb'
@@ -2083,6 +2069,7 @@ Style/MethodDefParentheses:
20832069
- 'lib/solargraph/type_checker/checks.rb'
20842070
- 'lib/solargraph/yard_map/helpers.rb'
20852071
- 'lib/solargraph/yardoc.rb'
2072+
- 'spec/doc_map_spec.rb'
20862073
- 'spec/fixtures/rdoc-lib/lib/example.rb'
20872074
- 'spec/source_map_spec.rb'
20882075
- 'spec/spec_helper.rb'
@@ -2412,7 +2399,6 @@ Style/StringConcatenation:
24122399
Exclude:
24132400
- 'lib/solargraph/api_map.rb'
24142401
- 'lib/solargraph/api_map/index.rb'
2415-
- 'lib/solargraph/convention/struct_definition.rb'
24162402
- 'lib/solargraph/pin/base.rb'
24172403
- 'lib/solargraph/pin/callable.rb'
24182404
- 'lib/solargraph/pin/closure.rb'
@@ -2494,6 +2480,7 @@ Style/StringLiterals:
24942480
- 'spec/rbs_map/conversions_spec.rb'
24952481
- 'spec/rbs_map/core_map_spec.rb'
24962482
- 'spec/rbs_map/stdlib_map_spec.rb'
2483+
- 'spec/shell_spec.rb'
24972484
- 'spec/source/chain/array_spec.rb'
24982485
- 'spec/source/chain/call_spec.rb'
24992486
- 'spec/source/chain/class_variable_spec.rb'
@@ -2598,7 +2585,6 @@ Style/TrailingCommaInArrayLiteral:
25982585
# SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
25992586
Style/TrailingCommaInHashLiteral:
26002587
Exclude:
2601-
- 'lib/solargraph/pin/base.rb'
26022588
- 'lib/solargraph/pin/base_variable.rb'
26032589
- 'lib/solargraph/pin/callable.rb'
26042590
- 'lib/solargraph/pin/closure.rb'
@@ -2628,6 +2614,7 @@ Style/WordArray:
26282614
- 'lib/solargraph/complex_type/unique_type.rb'
26292615
- 'lib/solargraph/diagnostics/type_check.rb'
26302616
- 'lib/solargraph/language_server/message/text_document/formatting.rb'
2617+
- 'spec/doc_map_spec.rb'
26312618
- 'spec/parser/node_chainer_spec.rb'
26322619
- 'spec/pin/method_spec.rb'
26332620
- 'spec/source/cursor_spec.rb'
@@ -2664,18 +2651,12 @@ YARD/CollectionType:
26642651
# SupportedStylesPrototypeName: before, after
26652652
YARD/MismatchName:
26662653
Exclude:
2667-
- 'lib/solargraph/api_map.rb'
26682654
- 'lib/solargraph/complex_type.rb'
26692655
- 'lib/solargraph/complex_type/unique_type.rb'
2670-
- 'lib/solargraph/convention.rb'
2671-
- 'lib/solargraph/convention/data_definition.rb'
2672-
- 'lib/solargraph/doc_map.rb'
26732656
- 'lib/solargraph/gem_pins.rb'
26742657
- 'lib/solargraph/language_server/host.rb'
26752658
- 'lib/solargraph/language_server/host/dispatch.rb'
2676-
- 'lib/solargraph/language_server/message/text_document/formatting.rb'
26772659
- 'lib/solargraph/language_server/request.rb'
2678-
- 'lib/solargraph/parser/flow_sensitive_typing.rb'
26792660
- 'lib/solargraph/parser/parser_gem/node_methods.rb'
26802661
- 'lib/solargraph/parser/region.rb'
26812662
- 'lib/solargraph/pin/base.rb'
@@ -2693,8 +2674,6 @@ YARD/MismatchName:
26932674
- 'lib/solargraph/pin/until.rb'
26942675
- 'lib/solargraph/pin/while.rb'
26952676
- 'lib/solargraph/pin_cache.rb'
2696-
- 'lib/solargraph/rbs_map.rb'
2697-
- 'lib/solargraph/shell.rb'
26982677
- 'lib/solargraph/source/chain.rb'
26992678
- 'lib/solargraph/source/chain/call.rb'
27002679
- 'lib/solargraph/source/chain/z_super.rb'

lib/solargraph/convention/struct_definition.rb

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def process
2020
name: struct_definition_node.class_name,
2121
docstring: docstring,
2222
visibility: :public,
23-
gates: region.closure.gates.freeze
23+
gates: region.closure.gates.freeze,
24+
source: :struct_definition
2425
)
2526
pins.push nspin
2627

@@ -32,7 +33,8 @@ def process
3233
location: get_node_location(node),
3334
closure: nspin,
3435
visibility: :private,
35-
docstring: docstring
36+
docstring: docstring,
37+
source: :struct_definition
3638
)
3739

3840
pins.push initialize_method_pin
@@ -43,7 +45,8 @@ def process
4345
name: attribute_name,
4446
decl: struct_definition_node.keyword_init? ? :kwarg : :arg,
4547
location: get_node_location(attribute_node),
46-
closure: initialize_method_pin
48+
closure: initialize_method_pin,
49+
source: :struct_definition
4750
)
4851
)
4952
end
@@ -53,29 +56,40 @@ def process
5356
[attribute_name, "#{attribute_name}="].each do |name|
5457
docs = docstring.tags.find { |t| t.tag_name == 'param' && t.name == attribute_name }
5558

59+
attribute_type = ComplexType.parse(tag_string(docs))
60+
return_type_comment = attribute_comment(docs, false)
61+
param_comment = attribute_comment(docs, true)
62+
5663
method_pin = Pin::Method.new(
5764
name: name,
5865
parameters: [],
5966
scope: :instance,
6067
location: get_node_location(attribute_node),
6168
closure: nspin,
69+
docstring: YARD::Docstring.new(return_type_comment),
6270
# even assignments return the value
63-
comments: attribute_comment(docs, false),
64-
visibility: :public
71+
comments: return_type_comment,
72+
return_type: attribute_type,
73+
visibility: :public,
74+
source: :struct_definition
6575
)
6676

6777
if name.end_with?('=')
6878
method_pin.parameters << Pin::Parameter.new(
6979
name: attribute_name,
7080
location: get_node_location(attribute_node),
71-
closure: nspin,
72-
comments: attribute_comment(docs, true)
81+
closure: method_pin,
82+
return_type: attribute_type,
83+
comments: param_comment,
84+
source: :struct_definition
7385
)
7486

7587
pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
7688
closure: method_pin,
7789
location: get_node_location(attribute_node),
78-
comments: attribute_comment(docs, false))
90+
return_type: attribute_type,
91+
comments: "@type [#{attribute_type.rooted_tags}]",
92+
source: :struct_definition)
7993
end
8094

8195
pins.push method_pin
@@ -121,13 +135,21 @@ def parse_comments
121135
Solargraph::Source.parse_docstring(struct_comments).to_docstring
122136
end
123137

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+
124145
# @param tag [YARD::Tags::Tag, nil] The param tag for this attribute. If nil, this method is a no-op
125146
# @param for_setter [Boolean] If true, will return a @param tag instead of a @return tag
147+
#
126148
# @return [String] The formatted comment for the attribute
127149
def attribute_comment(tag, for_setter)
128150
return "" if tag.nil?
129151

130-
suffix = "[#{tag.types&.join(',') || 'undefined'}] #{tag.text}"
152+
suffix = "[#{tag_string(tag)}] #{tag.text}"
131153

132154
if for_setter
133155
"@param #{tag.name} #{suffix}"

spec/convention/struct_definition_spec.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@
2121
expect(param_baz.return_type.tag).to eql('Integer')
2222
end
2323

24+
it 'should set closure to method on assignment operator parameters' do
25+
source = Solargraph::SourceMap.load_string(%(
26+
# @param bar [String]
27+
# @param baz [Integer]
28+
Foo = Struct.new(:bar, :baz, keyword_init: true)
29+
), 'test.rb')
30+
31+
# @type [Array<Solargraph::Pin::Parameter>]
32+
parameters = source.pins.find { |p| p.path == 'Foo#bar=' }.parameters
33+
34+
parameters.each do |param|
35+
expect(param.closure).to be_instance_of(Solargraph::Pin::Method)
36+
end
37+
end
38+
2439
it 'supports positional args' do
2540
source = Solargraph::SourceMap.load_string(%(
2641
# @param bar [String]
@@ -110,7 +125,26 @@
110125
expect(params_baz.length).to be(1)
111126
expect(params_baz.first.return_type.tag).to eql("Integer")
112127
expect(params_baz.first.arg?).to be(true)
128+
129+
iv_bar = source.pins.find { |p| p.name == "@bar" }
130+
expect(iv_bar.return_type.tag).to eql("String")
131+
132+
iv_baz = source.pins.find { |p| p.name == "@baz" }
133+
expect(iv_baz.return_type.tag).to eql("Integer")
113134
end
114135
end
115136
end
137+
138+
context 'with typechecking' do
139+
def type_checker code
140+
Solargraph::TypeChecker.load_string(code, 'test.rb', :strong)
141+
end
142+
143+
it 'should not crash' do
144+
checker = type_checker(%(
145+
Foo = Struct.new(:bar, :baz)
146+
))
147+
expect { checker.problems }.not_to raise_error
148+
end
149+
end
116150
end

0 commit comments

Comments
 (0)