Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/rbs/environment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,26 @@ def normalize_module_name?(name)
when ClassEntry, ModuleEntry
type_name
when ClassAliasEntry, ModuleAliasEntry
normalize_module_name?(entry.decl.old_name)
i = 0
outer_paths = entry.outer.map { |outer| outer.name.to_namespace.path }
old_name_namespace = entry.decl.old_name.namespace
old_name_bottom = entry.decl.old_name.name
n = nil #: ::RBS::TypeName | nil | false
loop do
outer_path = outer_paths[-i, i] or raise
t = TypeName.new(
namespace: Namespace.new(
absolute: false,
path: outer_path.flatten
) + old_name_namespace,
name: old_name_bottom
)
n = normalize_module_name?(t)
break if n
i += 1
break if outer_paths.length < i
end
n
else
nil
end
Expand Down
9 changes: 9 additions & 0 deletions lib/rbs/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,20 @@ def validate_variable(var)
def validate_class_alias(entry:)
case env.normalize_module_name?(entry.decl.new_name)
when nil
# Unreachable?
raise NoTypeFoundError.new(type_name: entry.decl.old_name, location: entry.decl.location&.[](:old_name))
when false
raise CyclicClassAliasDefinitionError.new(entry)
end

case env.normalize_module_name?(entry.decl.old_name)
when nil
raise NoTypeFoundError.new(type_name: entry.decl.old_name, location: entry.decl.location&.[](:old_name))
when false
# Unreachable?
raise CyclicClassAliasDefinitionError.new(entry)
end

case entry
when Environment::ClassAliasEntry
unless env.class_entry(entry.decl.old_name)
Expand Down
32 changes: 32 additions & 0 deletions test/rbs/cli_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,38 @@ def void: () -> voida
end
end

# https://github.com/ruby/rbs/issues/2293
def test_nested_module_alias
with_cli do |cli|
Dir.mktmpdir do |dir|
(Pathname(dir) + 'a.rbs').write(<<~RBS)
module Foo
module Bar
module M
end
module M2 = M
end

module Baz = Bar

module Bar::N = Bar::M

module X = Nothing
end

module Foo::Qux = Foo::Baz

module Foo::Y = Foo::Nothing
RBS
assert_raises SystemExit do
cli.run(["-I", dir, "validate"])
end
assert_include stdout.string, "a.rbs:12:13...12:20: Could not find Nothing (RBS::NoTypeFoundError)"
assert_include stdout.string, "a.rbs:17:16...17:28: Could not find Foo::Nothing (RBS::NoTypeFoundError)"
end
end
end

def test_constant
with_cli do |cli|
cli.run(%w(constant Pathname))
Expand Down
59 changes: 59 additions & 0 deletions test/validator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,65 @@ class Baz = Baz
end
end

# https://github.com/ruby/rbs/issues/2293
def test_validate_class_alias_in_namespace
SignatureManager.new do |manager|
manager.add_file("foo.rbs", <<-EOF)
module Foo
module Bar
module M
end
module M2 = M
end

module Baz = Bar

module Bar::N = Bar::M

module X = Nothing
end

module Foo::Qux = Foo::Baz

module Foo::Y = Foo::Nothing
EOF

manager.build do |env|
validator = RBS::Validator.new(env: env)
env.class_alias_decls[RBS::TypeName.parse("::Foo::Baz")].tap do |entry|
assert_nothing_raised do
validator.validate_class_alias(entry: entry)
end
end
env.class_alias_decls[RBS::TypeName.parse("::Foo::Bar::N")].tap do |entry|
assert_nothing_raised do
validator.validate_class_alias(entry: entry)
end
end
env.class_alias_decls[RBS::TypeName.parse("::Foo::Bar::M2")].tap do |entry|
assert_nothing_raised do
validator.validate_class_alias(entry: entry)
end
end
env.class_alias_decls[RBS::TypeName.parse("::Foo::Qux")].tap do |entry|
assert_nothing_raised do
validator.validate_class_alias(entry: entry)
end
end
env.class_alias_decls[RBS::TypeName.parse("::Foo::X")].tap do |entry|
assert_raises RBS::NoTypeFoundError do
validator.validate_class_alias(entry: entry)
end
end
env.class_alias_decls[RBS::TypeName.parse("::Foo::Y")].tap do |entry|
assert_raises RBS::NoTypeFoundError do
validator.validate_class_alias(entry: entry)
end
end
end
end
end

def test_validate_type__presence__module_alias_instance
SignatureManager.new do |manager|
manager.add_file("foo.rbs", <<-EOF)
Expand Down