Skip to content

Commit

Permalink
Handle private constants in the index (#1003)
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Sep 15, 2023
1 parent 9a7cd11 commit 8de6f2a
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/ruby_indexer/lib/ruby_indexer/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,16 @@ class Entry
sig { returns(T::Array[String]) }
attr_reader :comments

sig { returns(Symbol) }
attr_accessor :visibility

sig { params(name: String, file_path: String, location: YARP::Location, comments: T::Array[String]).void }
def initialize(name, file_path, location, comments)
@name = name
@file_path = file_path
@location = location
@comments = comments
@visibility = T.let(:public, Symbol)
end

sig { returns(String) }
Expand Down
25 changes: 25 additions & 0 deletions lib/ruby_indexer/lib/ruby_indexer/visitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def visit(node)
add_constant(node)
when YARP::ConstantPathWriteNode, YARP::ConstantPathOrWriteNode
add_constant_with_path(node)
when YARP::CallNode
message = node.message
handle_private_constant(node) if message == "private_constant"
end
end

Expand All @@ -50,6 +53,28 @@ def visit_all(nodes)

private

sig { params(node: YARP::CallNode).void }
def handle_private_constant(node)
arguments = node.arguments&.arguments
return unless arguments

first_argument = arguments.first

name = case first_argument
when YARP::StringNode
first_argument.content
when YARP::SymbolNode
first_argument.value
end

return unless name

# The private_constant method does not resolve the constant name. It always points to a constant that needs to
# exist in the current namespace
entries = @index[fully_qualify_name(name)]
entries&.each { |entry| entry.visibility = :private }
end

sig do
params(
node: T.any(YARP::ConstantWriteNode, YARP::ConstantOrWriteNode),
Expand Down
23 changes: 23 additions & 0 deletions lib/ruby_indexer/test/classes_and_modules_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,28 @@ class Bar; end
second_foo_entry = @index["Bar"][0]
assert_equal("This is a Bar comment", second_foo_entry.comments.join("\n"))
end

def test_private_class_and_module_indexing
index(<<~RUBY)
class A
class B; end
private_constant(:B)
module C; end
private_constant("C")
class D; end
end
RUBY

b_const = @index["A::B"].first
assert_equal(:private, b_const.visibility)

c_const = @index["A::C"].first
assert_equal(:private, c_const.visibility)

d_const = @index["A::D"].first
assert_equal(:public, d_const.visibility)
end
end
end
56 changes: 56 additions & 0 deletions lib/ruby_indexer/test/constant_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,61 @@ def test_variable_path_constants_are_ignored

assert_no_entry
end

def test_private_constant_indexing
index(<<~RUBY)
class A
B = 1
private_constant(:B)
C = 2
private_constant("C")
D = 1
end
RUBY

b_const = @index["A::B"].first
assert_equal(:private, b_const.visibility)

c_const = @index["A::C"].first
assert_equal(:private, c_const.visibility)

d_const = @index["A::D"].first
assert_equal(:public, d_const.visibility)
end

def test_marking_constants_as_private_reopening_namespaces
index(<<~RUBY)
module A
module B
CONST_A = 1
private_constant(:CONST_A)
CONST_B = 2
CONST_C = 3
end
module B
private_constant(:CONST_B)
end
end
module A
module B
private_constant(:CONST_C)
end
end
RUBY

b_const = @index["A::B::CONST_A"].first
assert_equal(:private, b_const.visibility)

c_const = @index["A::B::CONST_B"].first
assert_equal(:private, c_const.visibility)

d_const = @index["A::B::CONST_C"].first
assert_equal(:private, d_const.visibility)
end
end
end

0 comments on commit 8de6f2a

Please sign in to comment.