# typed: strict# frozen_string_literal: truerequire"set"moduleSpoommoduleDeadcodemodulePluginsclassBaseextendT::SigextendT::Helpersabstract!class<<selfextendT::Sig# Plugins DSL# Mark methods matching `names` as ignored.## Names can be either strings or regexps:## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# ignore_method_names(# "foo",# "bar",# /baz.*/,# )# end# ~~~sig{params(names: T.any(String,Regexp)).void}defignore_method_names(*names)save_names_and_patterns(names,:@ignored_method_names,:@ignored_method_patterns)endprivatesig{params(names: T::Array[T.any(String,Regexp)],names_variable: Symbol,patterns_variable: Symbol).void}defsave_names_and_patterns(names,names_variable,patterns_variable)ignored_names=instance_variable_set(names_variable,Set.new)ignored_patterns=instance_variable_set(patterns_variable,[])names.eachdo|name|casenamewhenStringignored_names<<namewhenRegexpignored_patterns<<nameendendendend# Indexing event methods# Called when an accessor is defined.## Will be called when the indexer processes a `attr_reader`, `attr_writer` or `attr_accessor` node.# Note that when this method is called, the definition for the node has already been added to the index.# It is still possible to ignore it from the plugin:## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# def on_define_accessor(indexer, definition)# definition.ignored! if definition.name == "foo"# end# end# ~~~sig{params(indexer: Indexer,definition: Definition).void}defon_define_accessor(indexer,definition)# no-opend# Called when a class is defined.## Will be called when the indexer processes a `class` node.# Note that when this method is called, the definition for the node has already been added to the index.# It is still possible to ignore it from the plugin:## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# def on_define_class(indexer, definition)# definition.ignored! if definition.name == "Foo"# end# end# ~~~sig{params(indexer: Indexer,definition: Definition).void}defon_define_class(indexer,definition)# no-opend# Called when a constant is defined.## Will be called when the indexer processes a `CONST =` node.# Note that when this method is called, the definition for the node has already been added to the index.# It is still possible to ignore it from the plugin:## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# def on_define_constant(indexer, definition)# definition.ignored! if definition.name == "FOO"# end# end# ~~~sig{params(indexer: Indexer,definition: Definition).void}defon_define_constant(indexer,definition)# no-opend# Called when a method is defined.## Will be called when the indexer processes a `def` or `defs` node.# Note that when this method is called, the definition for the node has already been added to the index.# It is still possible to ignore it from the plugin:## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# def on_define_method(indexer, definition)# super # So the `ignore_method_names` DSL is still applied## definition.ignored! if definition.name == "foo"# end# end# ~~~sig{params(indexer: Indexer,definition: Definition).void}defon_define_method(indexer,definition)definition.ignored!ifignored_method_name?(definition.name)end# Called when a module is defined.## Will be called when the indexer processes a `module` node.# Note that when this method is called, the definition for the node has already been added to the index.# It is still possible to ignore it from the plugin:## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# def on_define_module(indexer, definition)# definition.ignored! if definition.name == "Foo"# end# end# ~~~sig{params(indexer: Indexer,definition: Definition).void}defon_define_module(indexer,definition)# no-opend# Called when a send is being processed## ~~~rb# class MyPlugin < Spoom::Deadcode::Plugins::Base# def on_send(indexer, send)# return unless send.name == "dsl_method"# return if send.args.empty?## method_name = indexer.node_string(send.args.first).delete_prefix(":")# indexer.reference_method(method_name, send.node)# end# end# ~~~sig{params(indexer: Indexer,send: Send).void}defon_send(indexer,send)# no-opendprivatesig{params(name: String).returns(T::Boolean)}defignored_method_name?(name)ignored_name?(name,:@ignored_method_names,:@ignored_method_patterns)endsig{params(const: Symbol).returns(T::Set[String])}defnames(const)self.class.instance_variable_get(const)||Set.newendsig{params(name: String,names_variable: Symbol,patterns_variable: Symbol).returns(T::Boolean)}defignored_name?(name,names_variable,patterns_variable)names(names_variable).include?(name)||patterns(patterns_variable).any?{|pattern|pattern.match?(name)}endsig{params(const: Symbol).returns(T::Array[Regexp])}defpatterns(const)self.class.instance_variable_get(const)||[]endsig{params(indexer: Indexer,send: Send).void}defreference_send_first_symbol_as_method(indexer,send)first_arg=send.args.firstreturnunlessfirst_arg.is_a?(SyntaxTree::SymbolLiteral)name=indexer.node_string(first_arg.value)indexer.reference_method(name,send.node)endendendendend