Skip to content

Commit

Permalink
Merge pull request #571 from Shopify/at-deadcode-refs-visitor
Browse files Browse the repository at this point in the history
Deadcode indexing relies on `Model::ReferencesVisitor`
  • Loading branch information
Morriar authored Jul 4, 2024
2 parents 547c005 + 951900a commit 104d0c9
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 286 deletions.
9 changes: 2 additions & 7 deletions lib/spoom/cli/deadcode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,11 @@ def deadcode(*paths)

$stderr.puts "Indexing #{blue(files.size.to_s)} files..."
files.each do |file|
content = File.read(file)
content = Spoom::Deadcode::ERB.new(content).src if file.end_with?(".erb")

tree = Spoom.parse_ruby(content, file: file)
Spoom::Model::Builder.new(model, file).visit(tree)
Spoom::Deadcode.index_node(index, tree, content, file: file, plugins: plugins)
index.index_file(file, plugins: plugins)
rescue ParseError => e
say_error("Error parsing #{file}: #{e.message}")
next
rescue Spoom::Deadcode::IndexerError => e
rescue Spoom::Deadcode::Index::Error => e
say_error("Error indexing #{file}: #{e.message}")
next
end
Expand Down
54 changes: 0 additions & 54 deletions lib/spoom/deadcode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,6 @@
require_relative "deadcode/indexer"

require_relative "deadcode/definition"
require_relative "deadcode/reference"
require_relative "deadcode/send"
require_relative "deadcode/plugins"
require_relative "deadcode/remover"

module Spoom
module Deadcode
class Error < Spoom::Error
extend T::Helpers

abstract!
end

class IndexerError < Error
extend T::Sig

sig { params(message: String, parent: Exception).void }
def initialize(message, parent:)
super(message)
set_backtrace(parent.backtrace)
end
end

class << self
extend T::Sig

sig do
params(
index: Index,
node: Prism::Node,
ruby: String,
file: String,
plugins: T::Array[Deadcode::Plugins::Base],
).void
end
def index_node(index, node, ruby, file:, plugins: [])
visitor = Spoom::Deadcode::Indexer.new(file, ruby, index, plugins: plugins)
visitor.visit(node)
rescue => e
raise IndexerError.new("Error while indexing #{file} (#{e.message})", parent: e)
end

sig { params(index: Index, ruby: String, file: String, plugins: T::Array[Deadcode::Plugins::Base]).void }
def index_ruby(index, ruby, file:, plugins: [])
node = Spoom.parse_ruby(ruby, file: file)
Model::Builder.new(index.model, file).visit(node)
index_node(index, node, ruby, file: file, plugins: plugins)
end

sig { params(index: Index, erb: String, file: String, plugins: T::Array[Deadcode::Plugins::Base]).void }
def index_erb(index, erb, file:, plugins: [])
ruby = ERB.new(erb).src
index_ruby(index, ruby, file: file, plugins: plugins)
end
end
end
end
60 changes: 55 additions & 5 deletions lib/spoom/deadcode/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,88 @@ module Deadcode
class Index
extend T::Sig

class Error < Spoom::Error
extend T::Sig

sig { params(message: String, parent: Exception).void }
def initialize(message, parent:)
super(message)
set_backtrace(parent.backtrace)
end
end

sig { returns(Model) }
attr_reader :model

sig { returns(T::Hash[String, T::Array[Definition]]) }
attr_reader :definitions

sig { returns(T::Hash[String, T::Array[Reference]]) }
sig { returns(T::Hash[String, T::Array[Model::Reference]]) }
attr_reader :references

sig { params(model: Model).void }
def initialize(model)
@model = model
@definitions = T.let({}, T::Hash[String, T::Array[Definition]])
@references = T.let({}, T::Hash[String, T::Array[Reference]])
@references = T.let({}, T::Hash[String, T::Array[Model::Reference]])
@ignored = T.let(Set.new, T::Set[Model::SymbolDef])
end

# Indexing

sig { params(file: String, plugins: T::Array[Plugins::Base]).void }
def index_file(file, plugins: [])
if file.end_with?(".erb")
erb = File.read(file)
index_erb(erb, file: file, plugins: plugins)
else
rb = File.read(file)
index_ruby(rb, file: file, plugins: plugins)
end
end

sig { params(erb: String, file: String, plugins: T::Array[Plugins::Base]).void }
def index_erb(erb, file:, plugins: [])
index_ruby(Deadcode::ERB.new(erb).src, file: file, plugins: plugins)
end

sig { params(rb: String, file: String, plugins: T::Array[Plugins::Base]).void }
def index_ruby(rb, file:, plugins: [])
node = Spoom.parse_ruby(rb, file: file)

# Index definitions
model_builder = Model::Builder.new(@model, file)
model_builder.visit(node)

# Index references
refs_visitor = Model::ReferencesVisitor.new(file)
refs_visitor.visit(node)
refs_visitor.references.each do |ref|
(@references[ref.name] ||= []) << ref
end

# Index references and sends
indexer = Indexer.new(file, self, plugins: plugins)
indexer.visit(node)
rescue ParseError => e
raise e
rescue => e
raise Error.new("Error while indexing #{file} (#{e.message})", parent: e)
end

sig { params(definition: Definition).void }
def define(definition)
(@definitions[definition.name] ||= []) << definition
end

sig { params(name: String, location: Location).void }
def reference_constant(name, location)
(@references[name] ||= []) << Reference.new(name: name, kind: Reference::Kind::Constant, location: location)
(@references[name] ||= []) << Model::Reference.constant(name, location)
end

sig { params(name: String, location: Location).void }
def reference_method(name, location)
(@references[name] ||= []) << Reference.new(name: name, kind: Reference::Kind::Method, location: location)
(@references[name] ||= []) << Model::Reference.method(name, location)
end

sig { params(symbol_def: Model::SymbolDef).void }
Expand Down Expand Up @@ -170,7 +220,7 @@ def all_definitions
@definitions.values.flatten
end

sig { returns(T::Array[Reference]) }
sig { returns(T::Array[Model::Reference]) }
def all_references
@references.values.flatten
end
Expand Down
Loading

0 comments on commit 104d0c9

Please sign in to comment.