Module: RuboCop::Cop::ProjectIndexHelp
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Included In:
Lint::ConstantReassignment,
Lint::ConstantResolution,
Lint::DeprecatedReference,
Lint::DuplicateMethods,
Lint::InheritException,
Lint::MissingSuper,
Lint::UnusedPrivateMethod,
Naming::AccessorMethodName,
Naming::PredicatePrefix,
Style::ClassAndModuleChildren,
Style::Documentation,
Style::MissingRespondToMissing,
Style::RedundantConstantBase,
Style::StaticClass
| |
| Defined in: | lib/rubocop/cop/mixin/project_index_help.rb |
Overview
Common helpers for cops that consult the project-wide static-analysis index via Base#project_index.
Mixed-in cops gain the #external_dependency_checksum override that invalidates
the ::RuboCop::ResultCache whenever the indexed project files change on disk.
To run index-backed analysis, cops should simply check whether project_index is non-nil;
the runner only exposes a non-nil index when the user opted in via AllCops/UseProjectIndex
and the underlying gem is available.
Constant Summary
-
BUILTIN_DOCUMENT_URI =
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 14'rubydex:built-in' -
FILE_URI_PREFIX =
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 15'file://' -
WINDOWS_DRIVE_PREFIX =
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 18
Matches the spurious leading slash before a Windows drive letter that remains after stripping file:// from a file:///C:/… URI.
%r{\A/(?=[A-Za-z]:[/\\])}.freeze
Class Attribute Summary
-
.cached_index_signature
rw
The signature is a property of the index, not of the cop, and computing it stats every indexed file, so all cops sharing an index share one computation.
Instance Method Summary
- #external_dependency_checksum
- #compute_project_index_signature private
-
#definitions_in_other_files(definitions)
private
Returns the definitions among
definitionsthat live in a file other than the one being inspected, ordered by path and line. -
#indexed_singleton_member(namespace, member_name)
private
A namespace without any singleton method has no singleton-class declaration of its own, so the lookup starts from the first ancestor that has one; its
find_membercovers the rest of the chain. -
#indexed_singleton_of(declaration)
private
The declaration of `declaration’s singleton class, or nil when no singleton method is defined on it anywhere in the project.
-
#inherited_index_member?(scope, member_name) ⇒ Boolean
private
Whether an ancestor of
scopeother thanscopeitself definesmember_name. -
#lexical_nesting_of(node)
private
The lexical nesting the node’s constants resolve through, outermost first.
- #prior_definition_in_other_file(definitions) private
- #project_index_signature private
-
#resolve_constant_in_index(const_node)
private
Resolves a constant node the way Ruby does: the first segment through the lexical nesting and every following segment inside the previous one.
- #same_file?(path, other) ⇒ Boolean private
Class Attribute Details
.cached_index_signature (rw)
The signature is a property of the index, not of the cop, and computing it stats every indexed file, so all cops sharing an index share one computation. A single-entry cache (instead of a hash keyed by index) avoids retaining stale graphs in long-lived processes.
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 25
attr_accessor :cached_index_signature
Instance Method Details
#compute_project_index_signature (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 138
def compute_project_index_signature project_index.documents.filter_map do |doc| uri = doc.uri next if uri == BUILTIN_DOCUMENT_URI path = uri.delete_prefix(FILE_URI_PREFIX).sub(WINDOWS_DRIVE_PREFIX, '') mtime, size = begin stat = File.stat(path) [stat.mtime.to_f, stat.size] rescue StandardError [0, 0] end "#{path}:#{mtime}:#{size}" end.sort end
#definitions_in_other_files(definitions) (private)
Returns the definitions among definitions that live in a file other than the
one being inspected, ordered by path and line. Definitions without a file://
URI (e.g. Rubydex’s built-in declarations) are ignored.
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 41
def definitions_in_other_files(definitions) current = processed_source.file_path definitions .select { |definition| definition.location.uri.start_with?(FILE_URI_PREFIX) } .reject { |definition| File.identical?(definition.location.to_file_path, current) } .sort_by do |definition| [definition.location.to_file_path, definition.location.start_line] end end
#external_dependency_checksum
[ GitHub ]# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 28
def external_dependency_checksum return nil unless project_index @external_dependency_checksum ||= Digest::SHA1.hexdigest( project_index_signature.join("\n") ) end
#indexed_singleton_member(namespace, member_name) (private)
A namespace without any singleton method has no singleton-class
declaration of its own, so the lookup starts from the first ancestor
that has one; its find_member covers the rest of the chain.
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 105
def indexed_singleton_member(namespace, member_name) namespace.ancestors.each do |ancestor| singleton = indexed_singleton_of(ancestor) return singleton.find_member(member_name) if singleton end nil end
#indexed_singleton_of(declaration) (private)
The declaration of `declaration’s singleton class, or nil when no singleton method is defined on it anywhere in the project.
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 98
def indexed_singleton_of(declaration) project_index["#{declaration.name}::<#{declaration.name.split('::').last}>"] end
#inherited_index_member?(scope, member_name) ⇒ Boolean (private)
Whether an ancestor of scope other than scope itself defines
member_name.
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 116
def inherited_index_member?(scope, member_name) scope.ancestors.any? do |ancestor| ancestor.name != scope.name && ancestor.member(member_name) end end
#lexical_nesting_of(node) (private)
The lexical nesting the node’s constants resolve through, outermost first. Only scopes whose body contains the node count: a class or module’s identifier and superclass expression are evaluated before its scope exists, so ancestors reached through them are excluded.
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 82
def lexical_nesting_of(node) nesting = [] child = node node.each_ancestor do |ancestor| if ancestor.type?(:class, :module) && child.equal?(ancestor.body) nesting << ancestor.identifier.const_name end child = ancestor end nesting.reverse end
#prior_definition_in_other_file(definitions) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 53
def prior_definition_in_other_file(definitions) definitions_in_other_files(definitions).first end
#project_index_signature (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 129
def project_index_signature index, signature = ProjectIndexHelp.cached_index_signature return signature if index.equal?(project_index) compute_project_index_signature.tap do |computed| ProjectIndexHelp.cached_index_signature = [project_index, computed] end end
#resolve_constant_in_index(const_node) (private)
Resolves a constant node the way Ruby does: the first segment through
the lexical nesting and every following segment inside the previous
one. (Qualified names cannot be passed to resolve_constant as a
whole, since it only applies the nesting to the full name. Later
segments use find_member — the namespace and its ancestors — since
resolve_constant cannot take an already-resolved namespace as the
scope, only names as they appear in source.)
# File 'lib/rubocop/cop/mixin/project_index_help.rb', line 64
def resolve_constant_in_index(const_node) segments = const_node.const_name.split('::') nesting = const_node.absolute? ? [] : lexical_nesting_of(const_node) declaration = project_index.resolve_constant(segments.first, nesting) segments.drop(1).each do |segment| return nil unless declaration.is_a?(Rubydex::Namespace) declaration = declaration.find_member(segment) end declaration end