Class: RuboCop::CommentConfig
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
SimpleForwardable
|
|
|
Instance Chain:
self,
PushPop,
DisableNext
|
|
| Inherits: | Object |
| Defined in: | lib/rubocop/comment_config.rb, lib/rubocop/comment_config/directive_range.rb, lib/rubocop/comment_config/disable_next.rb, lib/rubocop/comment_config/push_pop.rb |
Overview
This class parses the special rubocop:disable comments in a source
and provides a way to check if each cop is enabled at arbitrary line.
Constant Summary
-
CONFIG_DISABLED_LINE_RANGE_MIN =
# File 'lib/rubocop/comment_config.rb', line 11-Float::INFINITY
Class Method Summary
- .new(processed_source) ⇒ CommentConfig constructor
Instance Attribute Summary
- #processed_source readonly
Instance Method Summary
- #comment_only_line?(line_number) ⇒ Boolean
- #cop_disabled_line_ranges
- #cop_enabled_at_line?(cop, line_number) ⇒ Boolean
-
#cop_enabled_at_lines?(cop, first_line, last_line) ⇒ Boolean
Whether the cop is enabled for all of the given line span.
- #cop_opted_in?(cop) ⇒ Boolean
- #extra_enabled_comments
-
#opt_in_cops ⇒ Set<String>
Internal use only
The names of the cops that are opted in by an
enablecomment directive or a+argument of apush/nextdirective, used to mobilize cops disabled in the config on demand. -
#analyze
private
rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity.
- #analyze_cop(analysis, directive) private
- #analyze_disabled(analysis, directive) private
- #analyze_rest(analysis, directive) private
- #analyze_single_line(analysis, directive) private
- #cop_line_ranges(analysis) private
- #each_directive private
- #extra_enabled_comments_with_names(extras:, names:) private
- #handle_enable_all(directive, names, extras) private
-
#handle_switch(directive, names, extras)
private
Collect cops that have been disabled or enabled by name in a directive comment so that
Lint/RedundantCopEnableDirectivecan register offenses correctly. - #inject_disabled_cops_directives(analyses) private
- #non_comment_token_line_numbers private
- #opted_in_by(directive) private
-
#prevent_directive_disabling?(cop_name) ⇒ Boolean
private
Style/DisableCopsWithinSourceCodeDirectivecannot be disabled via directive comments when it is explicitly enabled withEnabled: true. - #qualified_cop_name(cop_name) private
-
#self_closing_directive?(directive) ⇒ Boolean
private
Push/pop and next-statement directives close themselves, so they play no part in the disable/enable pairing.
PushPop - Included
DisableNext - Included
| #detached_next_directives | Next-statement directives that affect nothing: nothing follows them, or they sit at the end of a code line. |
| #statement_scope_after | The line range of the statement a |
| #add_next_range, #apply_disable_next, | |
| #apply_enable_next | Applies an |
| #apply_next_directive | Applies a |
| #attached_code_line, #heredoc?, #statement_bounds_at, #statement_end_line, #statement_start_line?, #statement_starting_at, | |
| #suspend_disable | Punches a statement-sized hole into the currently open disable of the cop (whether opened by a directive or injected for a config-disabled cop): the open range closes just above the statement and reopens right below it, still attributed to its opening directive. |
Constructor Details
.new(processed_source) ⇒ CommentConfig
# File 'lib/rubocop/comment_config.rb', line 34
def initialize(processed_source) @processed_source = processed_source @no_directives = !processed_source.raw_source.include?('rubocop') @stack = [] @detached_next_directives = [] end
Instance Attribute Details
#processed_source (readonly)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 30
attr_reader :processed_source
Instance Method Details
#analyze (private)
rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
# File 'lib/rubocop/comment_config.rb', line 126
def analyze return {} if @no_directives analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) } inject_disabled_cops_directives(analyses) each_directive do |directive| if directive.push? restore_point = analyses.transform_values(&:dup) @stack.push(restore_point) apply_push(analyses, resolve_push_cops(directive), directive) elsif directive.pop? pop_state(analyses, directive.line_number) if @stack.any? elsif directive.disable_next? apply_disable_next(analyses, directive) elsif directive.next? apply_next_directive(analyses, resolve_push_cops(directive), directive) elsif directive.enable_next? apply_enable_next(analyses, directive) else directive.cop_names.each do |cop_name| cop_name = qualified_cop_name(cop_name) analyses[cop_name] = analyze_cop(analyses[cop_name], directive) end end end analyses.each_with_object({}) do |element, hash| cop_name, analysis = *element next if prevent_directive_disabling?(cop_name) hash[cop_name] = cop_line_ranges(analysis) end end
#analyze_cop(analysis, directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 170
def analyze_cop(analysis, directive) # Disabling cops after comments like `#=SomeDslDirective` does not related to single line if !comment_only_line?(directive.line_number) || directive.single_line? analyze_single_line(analysis, directive) elsif directive.disabled? analyze_disabled(analysis, directive) else analyze_rest(analysis, directive) end end
#analyze_disabled(analysis, directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 190
def analyze_disabled(analysis, directive) CopAnalysis.new(analysis.close(directive.line_number), directive.line_number, directive) end
#analyze_rest(analysis, directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 194
def analyze_rest(analysis, directive) CopAnalysis.new(analysis.close(directive.line_number), nil) end
#analyze_single_line(analysis, directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 181
def analyze_single_line(analysis, directive) return analysis unless directive.disabled? line = directive.line_number range = DirectiveRange.new(line, line, directive) CopAnalysis.new(analysis.line_ranges + [range], analysis.start_line_number, analysis.start_directive) end
#comment_only_line?(line_number) ⇒ Boolean
# File 'lib/rubocop/comment_config.rb', line 75
def comment_only_line?(line_number) non_comment_token_line_numbers.none?(line_number) end
#cop_disabled_line_ranges
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 63
def cop_disabled_line_ranges @cop_disabled_line_ranges ||= analyze end
#cop_enabled_at_line?(cop, line_number) ⇒ Boolean
# File 'lib/rubocop/comment_config.rb', line 41
def cop_enabled_at_line?(cop, line_number) cop_enabled_at_lines?(cop, line_number, line_number) end
#cop_enabled_at_lines?(cop, first_line, last_line) ⇒ Boolean
Whether the cop is enabled for all of the given line span. The cop counts as disabled for the span when any of its disabled ranges overlaps it, so that a directive on any line of a multi-line offense suppresses the offense.
# File 'lib/rubocop/comment_config.rb', line 49
def cop_enabled_at_lines?(cop, first_line, last_line) cop = cop.cop_name if cop.respond_to?(:cop_name) disabled_line_ranges = cop_disabled_line_ranges[cop] return true unless disabled_line_ranges disabled_line_ranges.none? do |range| range.end >= first_line && range.begin <= last_line end end
#cop_line_ranges(analysis) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 198
def cop_line_ranges(analysis) analysis.close(Float::INFINITY) end
#cop_opted_in?(cop) ⇒ Boolean
# File 'lib/rubocop/comment_config.rb', line 59
def cop_opted_in?(cop) opt_in_cops.include?(cop.cop_name) end
#each_directive (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 202
def each_directive return if @no_directives processed_source.comments.each do |comment| directive = DirectiveComment.new(comment) yield directive if directive.cop_names end end
#extra_enabled_comments
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 67
def extra_enabled_comments disable_count = Hash.new(0) registry.disabled_names(config).each do |cop_name| disable_count[cop_name] += 1 end extra_enabled_comments_with_names(extras: Hash.new { |h, k| h[k] = [] }, names: disable_count) end
#extra_enabled_comments_with_names(extras:, names:) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 98
def extra_enabled_comments_with_names(extras:, names:) each_directive do |directive| next unless comment_only_line?(directive.line_number) next if self_closing_directive?(directive) if directive.enabled_all? handle_enable_all(directive, names, extras) else handle_switch(directive, names, extras) end end extras end
#handle_enable_all(directive, names, extras) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 243
def handle_enable_all(directive, names, extras) enabled_cops = 0 names.each do |name, counter| next unless counter.positive? names[name] -= 1 enabled_cops += 1 end extras[directive.comment] << 'all' if enabled_cops.zero? end
#handle_switch(directive, names, extras) (private)
Collect cops that have been disabled or enabled by name in a directive comment
so that Lint/RedundantCopEnableDirective can register offenses correctly.
# File 'lib/rubocop/comment_config.rb', line 257
def handle_switch(directive, names, extras) directive.cop_names.each do |name| if directive.disabled? names[name] += 1 elsif names[name].positive? names[name] -= 1 else extras[directive.comment] << name end end end
#inject_disabled_cops_directives(analyses) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 161
def inject_disabled_cops_directives(analyses) registry.disabled_names(config).each do |cop_name| analyses[cop_name] = analyze_cop( analyses[cop_name], DirectiveComment.new(ConfigDisabledCopDirectiveComment.new(cop_name)) ) end end
#non_comment_token_line_numbers (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 236
def non_comment_token_line_numbers @non_comment_token_line_numbers ||= begin non_comment_tokens = processed_source.tokens.reject(&:comment?) non_comment_tokens.map(&:line).uniq end end
#opt_in_cops ⇒ Set<String>
The names of the cops that are opted in by an enable comment directive
or a + argument of a push/next directive, used to mobilize cops
disabled in the config on demand. Departments are expanded for the
opt-in forms only: a plain enable naming a department usually just
closes a disable of it, and expanding it would switch on every
config-disabled cop of the department for the rest of the file.
# File 'lib/rubocop/comment_config.rb', line 88
def opt_in_cops @opt_in_cops ||= begin cops = Set.new each_directive { |directive| cops.merge(opted_in_by(directive)) } cops end end
#opted_in_by(directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 113
def opted_in_by(directive) if directive.push? || directive.next? directive.signed_args.fetch('+', []).flat_map { |name| (name) } elsif !directive.enabled? || directive.all_cops? [] elsif directive.enable_next? directive.cop_names else directive.raw_cop_names end end
#prevent_directive_disabling?(cop_name) ⇒ Boolean (private)
Style/DisableCopsWithinSourceCodeDirective cannot be disabled via
directive comments when it is explicitly enabled with Enabled: true.
This prevents users from bypassing the cop by writing a disable
directive that targets this cop itself.
# File 'lib/rubocop/comment_config.rb', line 231
def prevent_directive_disabling?(cop_name) cop_name == DirectiveComment::STYLE_DISABLE_COPS_DIRECTIVE_COP && config.dig(cop_name, 'Enabled') == true end
#qualified_cop_name(cop_name) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 218
def qualified_cop_name(cop_name) # A directive naming a cop under the wrong department is not honored - # the mistake is surfaced by `Lint/RedundantCopDisableDirective` (with a # did-you-mean hint) instead of a stderr warning that is easy to miss # and disappears entirely on cached runs. Cop::Registry.qualified_cop_name(cop_name.strip, processed_source.file_path, correct_namespace: false) end
#self_closing_directive?(directive) ⇒ Boolean (private)
Push/pop and next-statement directives close themselves, so they play no part in the disable/enable pairing.
# File 'lib/rubocop/comment_config.rb', line 213
def self_closing_directive?(directive) directive.push? || directive.pop? || directive.disable_next? || directive.next? || directive.enable_next? end