Skip to content

Commit e5549e6

Browse files
committed
Update Environment
1 parent 2ac02b9 commit e5549e6

File tree

3 files changed

+165
-2
lines changed

3 files changed

+165
-2
lines changed

lib/rbs/environment.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,24 @@ def insert_ruby_decl(decl, context:, namespace:)
424424

425425
constant_decls[name] = ConstantEntry.new(name: name, decl: decl, context: context)
426426

427+
when AST::Ruby::Declarations::ClassModuleAliasDecl
428+
name = decl.new_name.with_prefix(namespace)
429+
430+
if entry = constant_entry(name)
431+
case entry
432+
when ClassAliasEntry, ModuleAliasEntry, ConstantEntry
433+
raise DuplicatedDeclarationError.new(name, decl, entry.decl)
434+
when ClassEntry, ModuleEntry
435+
raise DuplicatedDeclarationError.new(name, decl, *entry.each_decl.to_a)
436+
end
437+
end
438+
439+
case decl.annotation
440+
when AST::Ruby::Annotations::ClassAliasAnnotation
441+
class_alias_decls[name] = ClassAliasEntry.new(name: name, decl: decl, context: context)
442+
when AST::Ruby::Annotations::ModuleAliasAnnotation
443+
class_alias_decls[name] = ModuleAliasEntry.new(name: name, decl: decl, context: context)
444+
end
427445
else
428446
raise "Unknown Ruby declaration type: #{decl.class}"
429447
end
@@ -745,6 +763,20 @@ def resolve_ruby_decl(resolver, decl, context:, prefix:)
745763
decl.type_annotation&.map_type_name {|name, _, _| absolute_type_name(resolver, nil, name, context: context) }
746764
)
747765

766+
when AST::Ruby::Declarations::ClassModuleAliasDecl
767+
full_name = decl.new_name.with_prefix(prefix)
768+
resolved_annotation = decl.annotation.map_type_name {|name, _, _| absolute_type_name(resolver, nil, name, context: context) }
769+
resolved_infered_name = decl.infered_old_name&.yield_self {|name| absolute_type_name(resolver, nil, name, context: context) }
770+
771+
AST::Ruby::Declarations::ClassModuleAliasDecl.new(
772+
decl.buffer,
773+
decl.node,
774+
full_name,
775+
resolved_infered_name,
776+
decl.leading_comment,
777+
resolved_annotation
778+
)
779+
748780
else
749781
raise "Unknown declaration type: #{decl.class}"
750782
end

sig/environment.rbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ module RBS
1212
def initialize: (name: N, decl: D, context: Resolver::context) -> void
1313
end
1414

15-
class ModuleAliasEntry < SingleEntry[TypeName, AST::Declarations::ModuleAlias]
15+
class ModuleAliasEntry < SingleEntry[TypeName, AST::Declarations::ModuleAlias | AST::Ruby::Declarations::ClassModuleAliasDecl]
1616
end
1717

18-
class ClassAliasEntry < SingleEntry[TypeName, AST::Declarations::ClassAlias]
18+
class ClassAliasEntry < SingleEntry[TypeName, AST::Declarations::ClassAlias | AST::Ruby::Declarations::ClassModuleAliasDecl]
1919
end
2020

2121
class InterfaceEntry < SingleEntry[TypeName, AST::Declarations::Interface]

test/rbs/environment_test.rb

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,4 +793,135 @@ class Object
793793
# Verify that Object class is created
794794
assert_operator resolved_env.class_decls, :key?, type_name("::Object")
795795
end
796+
797+
def test__ruby__class_alias_declarations
798+
result = parse_inline(<<~RUBY)
799+
class String
800+
end
801+
class Object
802+
end
803+
class Array
804+
end
805+
806+
# Basic class alias without explicit type name
807+
MyString = String #: class-alias
808+
809+
# Class alias with explicit type name
810+
MyObject = some_object_factory #: class-alias Object
811+
812+
# Class alias with namespace
813+
MyArray = Array #: class-alias
814+
815+
# Nested class alias
816+
module Container
817+
InnerString = String #: class-alias
818+
end
819+
RUBY
820+
821+
env = Environment.new
822+
env.add_source(RBS::Source::Ruby.new(result.buffer, result.prism_result, result.declarations, result.diagnostics))
823+
resolved_env = env.resolve_type_names
824+
825+
# Check basic class alias without explicit type name
826+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::MyString")
827+
resolved_env.class_alias_decls[type_name("::MyString")].tap do |entry|
828+
assert_instance_of Environment::ClassAliasEntry, entry
829+
assert_equal type_name("::MyString"), entry.name
830+
assert_equal type_name("::String"), entry.decl.old_name
831+
end
832+
833+
# Check class alias with explicit type name
834+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::MyObject")
835+
resolved_env.class_alias_decls[type_name("::MyObject")].tap do |entry|
836+
assert_instance_of Environment::ClassAliasEntry, entry
837+
assert_equal type_name("::MyObject"), entry.name
838+
assert_equal type_name("::Object"), entry.decl.old_name
839+
end
840+
841+
# Check class alias with Array
842+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::MyArray")
843+
resolved_env.class_alias_decls[type_name("::MyArray")].tap do |entry|
844+
assert_instance_of Environment::ClassAliasEntry, entry
845+
assert_equal type_name("::MyArray"), entry.name
846+
assert_equal type_name("::Array"), entry.decl.old_name
847+
end
848+
849+
# Check nested class alias
850+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::Container::InnerString")
851+
resolved_env.class_alias_decls[type_name("::Container::InnerString")].tap do |entry|
852+
assert_instance_of Environment::ClassAliasEntry, entry
853+
assert_equal type_name("::Container::InnerString"), entry.name
854+
assert_equal type_name("::String"), entry.decl.old_name
855+
end
856+
857+
# Verify Container module is created
858+
assert_operator resolved_env.class_decls, :key?, type_name("::Container")
859+
end
860+
861+
def test__ruby__module_alias_declarations
862+
result = parse_inline(<<~RUBY)
863+
module Kernel
864+
end
865+
866+
module Enumerable
867+
end
868+
869+
# Basic module alias without explicit type name
870+
MyKernel = Kernel #: module-alias
871+
872+
# Module alias with explicit type name
873+
MyEnum = some_enumerable_factory #: module-alias Enumerable
874+
RUBY
875+
876+
env = Environment.new
877+
env.add_source(RBS::Source::Ruby.new(result.buffer, result.prism_result, result.declarations, result.diagnostics))
878+
resolved_env = env.resolve_type_names
879+
880+
# Check basic module alias without explicit type name
881+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::MyKernel")
882+
resolved_env.class_alias_decls[type_name("::MyKernel")].tap do |entry|
883+
assert_instance_of Environment::ModuleAliasEntry, entry
884+
assert_equal type_name("::MyKernel"), entry.name
885+
assert_equal type_name("::Kernel"), entry.decl.old_name
886+
end
887+
888+
# Check module alias with explicit type name
889+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::MyEnum")
890+
resolved_env.class_alias_decls[type_name("::MyEnum")].tap do |entry|
891+
assert_instance_of Environment::ModuleAliasEntry, entry
892+
assert_equal type_name("::MyEnum"), entry.name
893+
assert_equal type_name("::Enumerable"), entry.decl.old_name
894+
end
895+
end
896+
897+
def test__ruby__class_module_alias_with_skip_annotation
898+
result = parse_inline(<<~RUBY)
899+
# @rbs skip
900+
SkippedString = String #: class-alias
901+
902+
# This should be processed
903+
ProcessedString = String #: class-alias
904+
905+
# @rbs skip
906+
SkippedKernel = Kernel #: module-alias
907+
908+
# This should be processed
909+
ProcessedKernel = Kernel #: module-alias
910+
RUBY
911+
912+
env = Environment.new
913+
env.add_source(RBS::Source::Ruby.new(result.buffer, result.prism_result, result.declarations, result.diagnostics))
914+
resolved_env = env.resolve_type_names
915+
916+
# Check that skipped aliases are not present
917+
refute_operator resolved_env.class_alias_decls, :key?, type_name("::SkippedString")
918+
refute_operator resolved_env.class_alias_decls, :key?, type_name("::SkippedKernel")
919+
920+
# Check that non-skipped aliases are present
921+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::ProcessedString")
922+
assert_instance_of Environment::ClassAliasEntry, resolved_env.class_alias_decls[type_name("::ProcessedString")]
923+
924+
assert_operator resolved_env.class_alias_decls, :key?, type_name("::ProcessedKernel")
925+
assert_instance_of Environment::ModuleAliasEntry, resolved_env.class_alias_decls[type_name("::ProcessedKernel")]
926+
end
796927
end

0 commit comments

Comments
 (0)