Skip to content

Commit dcbb520

Browse files
committed
Implement parsing
1 parent 3d92378 commit dcbb520

File tree

4 files changed

+153
-7
lines changed

4 files changed

+153
-7
lines changed

lib/rbs/ast/ruby/members.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,27 @@ class AttrWriterMember < AttributeMember
294294

295295
class AttrAccessorMember < AttributeMember
296296
end
297+
298+
class InstanceVariableMember < Base
299+
attr_reader :annotation
300+
301+
def initialize(buffer, annotation)
302+
super(buffer)
303+
@annotation = annotation
304+
end
305+
306+
def name
307+
annotation.ivar_name
308+
end
309+
310+
def type
311+
annotation.type
312+
end
313+
314+
def location
315+
annotation.location
316+
end
317+
end
297318
end
298319
end
299320
end

lib/rbs/inline_parser.rb

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ def initialize(location, message)
3939
def self.parse(buffer, prism)
4040
result = Result.new(buffer, prism)
4141

42-
Parser.new(result).visit(prism.value)
42+
parser = Parser.new(result)
43+
parser.visit(prism.value)
44+
parser.comments.each_unassociated_block do |block|
45+
parser.report_unused_block(block)
46+
end
4347

4448
result
4549
end
@@ -111,11 +115,36 @@ def visit_class_node(node)
111115
insert_declaration(class_decl)
112116
push_module_nesting(class_decl) do
113117
visit_child_nodes(node)
118+
119+
node.child_nodes.each do |child_node|
120+
if child_node
121+
comments.each_enclosed_block(child_node) do |block|
122+
report_unused_block(block)
123+
end
124+
end
125+
end
114126
end
115127

116128
comments.each_enclosed_block(node) do |block|
117-
report_unused_block(block)
129+
unused_annotations = [] #: Array[AST::Ruby::CommentBlock::AnnotationSyntaxError | AST::Ruby::Annotations::leading_annotation]
130+
131+
block.each_paragraph([]) do |paragraph|
132+
case paragraph
133+
when AST::Ruby::Annotations::InstanceVariableAnnotation
134+
class_decl.members << AST::Ruby::Members::InstanceVariableMember.new(buffer, paragraph)
135+
when Location
136+
# Skip
137+
when AST::Ruby::CommentBlock::AnnotationSyntaxError
138+
unused_annotations << paragraph
139+
else
140+
unused_annotations << paragraph
141+
end
142+
end
143+
144+
report_unused_annotation(*unused_annotations)
118145
end
146+
147+
class_decl.members.sort_by! { _1.location.start_line }
119148
end
120149

121150
def visit_module_node(node)
@@ -169,7 +198,7 @@ def visit_def_node(node)
169198

170199
# Skip other comments in `def` node
171200
comments.each_enclosed_block(node) do |block|
172-
comments.associated_blocks << block
201+
report_unused_block(block)
173202
end
174203
else
175204
diagnostics << Diagnostic::TopLevelMethodDefinition.new(
@@ -208,8 +237,6 @@ def visit_call_node(node)
208237
end
209238
end
210239

211-
private
212-
213240
def parse_mixin_call(node)
214241
# Check for multiple arguments
215242
if node.arguments && node.arguments.arguments.length > 1
@@ -350,6 +377,8 @@ def report_unused_annotation(*annotations)
350377
end
351378

352379
def report_unused_block(block)
380+
return unless block.leading?
381+
353382
block.each_paragraph([]) do |paragraph|
354383
case paragraph
355384
when Location

sig/ast/ruby/members.rbs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module RBS
1313
type t = DefMember
1414
| IncludeMember | ExtendMember | PrependMember
1515
| AttrReaderMember | AttrWriterMember | AttrAccessorMember
16+
| InstanceVariableMember
1617

1718
class MethodTypeAnnotation
1819
class DocStyle
@@ -125,6 +126,18 @@ module RBS
125126

126127
class AttrAccessorMember < AttributeMember
127128
end
129+
130+
class InstanceVariableMember < Base
131+
attr_reader annotation: Annotations::InstanceVariableAnnotation
132+
133+
def initialize: (Buffer, Annotations::InstanceVariableAnnotation) -> void
134+
135+
def name: () -> Symbol
136+
137+
def type: () -> Types::t
138+
139+
def location: () -> Location
140+
end
128141
end
129142
end
130143
end

test/rbs/inline_parser_test.rb

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ def test_parse__class_with_super_class_and_members
10891089
result = parse(<<~RUBY)
10901090
class Person < ActiveRecord::Base #[Person]
10911091
attr_reader :name #: String
1092-
1092+
10931093
def age
10941094
25
10951095
end
@@ -1107,7 +1107,7 @@ def age
11071107
assert_equal "Person", decl.super_class.args[0].to_s
11081108

11091109
assert_equal 2, decl.members.size
1110-
1110+
11111111
decl.members[0].tap do |member|
11121112
assert_instance_of RBS::AST::Ruby::Members::AttrReaderMember, member
11131113
assert_equal [:name], member.names
@@ -1120,4 +1120,87 @@ def age
11201120
end
11211121
end
11221122
end
1123+
1124+
def test_parse__instance_variable
1125+
result = parse(<<~RUBY)
1126+
class Person
1127+
# @rbs @name: String
1128+
# @rbs @age: Integer?
1129+
1130+
def initialize(name, age)
1131+
@name = name
1132+
@age = age
1133+
end
1134+
end
1135+
RUBY
1136+
1137+
assert_empty result.diagnostics
1138+
1139+
result.declarations[0].tap do |decl|
1140+
assert_instance_of RBS::AST::Ruby::Declarations::ClassDecl, decl
1141+
assert_equal RBS::TypeName.parse("Person"), decl.class_name
1142+
1143+
# Should have 3 members: 2 instance variable members + 1 def member
1144+
assert_equal 3, decl.members.size
1145+
1146+
decl.members[0].tap do |member|
1147+
assert_instance_of RBS::AST::Ruby::Members::InstanceVariableMember, member
1148+
assert_equal :@name, member.name
1149+
assert_equal "String", member.type.to_s
1150+
assert_instance_of RBS::AST::Ruby::Annotations::InstanceVariableAnnotation, member.annotation
1151+
end
1152+
1153+
decl.members[1].tap do |member|
1154+
assert_instance_of RBS::AST::Ruby::Members::InstanceVariableMember, member
1155+
assert_equal :@age, member.name
1156+
assert_equal "Integer?", member.type.to_s
1157+
assert_instance_of RBS::AST::Ruby::Annotations::InstanceVariableAnnotation, member.annotation
1158+
end
1159+
1160+
decl.members[2].tap do |member|
1161+
assert_instance_of RBS::AST::Ruby::Members::DefMember, member
1162+
assert_equal :initialize, member.name
1163+
end
1164+
end
1165+
end
1166+
1167+
def test_error__instance_variable_ignored
1168+
result = parse(<<~RUBY)
1169+
# @rbs @global_decl: String
1170+
1171+
class Foo
1172+
def initialize
1173+
# @rbs @method_decl: Integer
1174+
end
1175+
1176+
tap do
1177+
# @rbs @block_decl: String
1178+
end
1179+
1180+
# @rbs @method_decl2: untyped
1181+
def foo
1182+
end
1183+
end
1184+
RUBY
1185+
1186+
assert_any!(result.diagnostics) do |diagnostic|
1187+
assert_instance_of RBS::InlineParser::Diagnostic::UnusedInlineAnnotation, diagnostic
1188+
assert_equal "@rbs @global_decl: String", diagnostic.location.source
1189+
end
1190+
1191+
assert_any!(result.diagnostics) do |diagnostic|
1192+
assert_instance_of RBS::InlineParser::Diagnostic::UnusedInlineAnnotation, diagnostic
1193+
assert_equal "@rbs @method_decl: Integer", diagnostic.location.source
1194+
end
1195+
1196+
assert_any!(result.diagnostics) do |diagnostic|
1197+
assert_instance_of RBS::InlineParser::Diagnostic::UnusedInlineAnnotation, diagnostic
1198+
assert_equal "@rbs @method_decl2: untyped", diagnostic.location.source
1199+
end
1200+
1201+
assert_any!(result.diagnostics) do |diagnostic|
1202+
assert_instance_of RBS::InlineParser::Diagnostic::UnusedInlineAnnotation, diagnostic
1203+
assert_equal "@rbs @block_decl: String", diagnostic.location.source
1204+
end
1205+
end
11231206
end

0 commit comments

Comments
 (0)