lib/spoom/deadcode/index.rb in spoom-1.3.2 vs lib/spoom/deadcode/index.rb in spoom-1.3.3
- old
+ new
@@ -4,41 +4,209 @@
module Spoom
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 { void }
- def initialize
+ 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(reference: Reference).void }
- def reference(reference)
- (@references[reference.name] ||= []) << reference
+ sig { params(name: String, location: Location).void }
+ def reference_constant(name, location)
+ (@references[name] ||= []) << Model::Reference.constant(name, location)
end
+ sig { params(name: String, location: Location).void }
+ def reference_method(name, location)
+ (@references[name] ||= []) << Model::Reference.method(name, location)
+ end
+
+ sig { params(symbol_def: Model::SymbolDef).void }
+ def ignore(symbol_def)
+ @ignored << symbol_def
+ end
+
+ sig { params(plugins: T::Array[Plugins::Base]).void }
+ def apply_plugins!(plugins)
+ @model.symbols.each do |_full_name, symbol|
+ symbol.definitions.each do |symbol_def|
+ case symbol_def
+ when Model::Class
+ plugins.each { |plugin| plugin.internal_on_define_class(symbol_def) }
+ when Model::Module
+ plugins.each { |plugin| plugin.internal_on_define_module(symbol_def) }
+ when Model::Constant
+ plugins.each { |plugin| plugin.internal_on_define_constant(symbol_def) }
+ when Model::Method
+ plugins.each { |plugin| plugin.internal_on_define_method(symbol_def) }
+ when Model::Attr
+ plugins.each { |plugin| plugin.internal_on_define_accessor(symbol_def) }
+ end
+ end
+ end
+ end
+
# Mark all definitions having a reference of the same name as `alive`
#
# To be called once all the files have been indexed and all the definitions and references discovered.
sig { void }
def finalize!
- @references.keys.each do |name|
- definitions_for_name(name).each(&:alive!)
+ @model.symbols.each do |_full_name, symbol|
+ symbol.definitions.each do |symbol_def|
+ case symbol_def
+ when Model::Class
+ definition = Definition.new(
+ kind: Definition::Kind::Class,
+ name: symbol.name,
+ full_name: symbol.full_name,
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ when Model::Module
+ definition = Definition.new(
+ kind: Definition::Kind::Module,
+ name: symbol.name,
+ full_name: symbol.full_name,
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ when Model::Constant
+ definition = Definition.new(
+ kind: Definition::Kind::Constant,
+ name: symbol.name,
+ full_name: symbol.full_name,
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ when Model::Method
+ definition = Definition.new(
+ kind: Definition::Kind::Method,
+ name: symbol.name,
+ full_name: symbol.full_name,
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ when Model::AttrAccessor
+ definition = Definition.new(
+ kind: Definition::Kind::AttrReader,
+ name: symbol.name,
+ full_name: symbol.full_name,
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+
+ definition = Definition.new(
+ kind: Definition::Kind::AttrWriter,
+ name: "#{symbol.name}=",
+ full_name: "#{symbol.full_name}=",
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ when Model::AttrReader
+ definition = Definition.new(
+ kind: Definition::Kind::AttrReader,
+ name: symbol.name,
+ full_name: symbol.full_name,
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ when Model::AttrWriter
+ definition = Definition.new(
+ kind: Definition::Kind::AttrWriter,
+ name: "#{symbol.name}=",
+ full_name: "#{symbol.full_name}=",
+ location: symbol_def.location,
+ )
+ definition.ignored! if @ignored.include?(symbol_def)
+ definition.alive! if @references.key?(symbol.name)
+ define(definition)
+ end
+ end
end
end
# Utils
@@ -50,10 +218,10 @@
sig { returns(T::Array[Definition]) }
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
end
end