Class: RuboCop::CommentConfig
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
SimpleForwardable
|
|
|
Instance Chain:
self,
DisableNext
|
|
| Inherits: | Object |
| Defined in: | lib/rubocop/comment_config.rb, lib/rubocop/comment_config/directive_range.rb, lib/rubocop/comment_config/disable_next.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 10-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, 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
- #apply_cop_op(analyses, operation, cop, directive) private
- #apply_push(analyses, resolved_cops, directive) private
- #cop_line_ranges(analysis) private
- #each_directive private
- #expand_cop_name(name) 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
- #pop_state(analyses, line) private
- #popped_analysis(current, restored, line) 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
- #resolve_push_cops(directive) private
DisableNext - Included
| #detached_next_directives |
|
| #statement_scope_after | The line range of the statement a |
| #add_next_range, #apply_disable_next, #attached_code_line, #heredoc?, #statement_bounds_at, #statement_end_line, #statement_start_line?, #statement_starting_at | |
Constructor Details
.new(processed_source) ⇒ CommentConfig
# File 'lib/rubocop/comment_config.rb', line 33
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 29
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 116
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) 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 198
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 218
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 222
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 209
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
#apply_cop_op(analyses, operation, cop, directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 165
def apply_cop_op(analyses, operation, cop, directive) analysis = analyses[cop] line = directive.line_number if operation == '-' && !analysis.start_line_number analyses[cop] = CopAnalysis.new(analysis.line_ranges, line, directive) elsif operation == '+' && analysis.start_line_number analyses[cop] = CopAnalysis.new(analysis.close(line), nil) end end
#apply_push(analyses, resolved_cops, directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 159
def apply_push(analyses, resolved_cops, directive) resolved_cops.each do |op, cops| cops.each { |cop| apply_cop_op(analyses, op, cop, directive) } end end
#comment_only_line?(line_number) ⇒ Boolean
# File 'lib/rubocop/comment_config.rb', line 74
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 62
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 40
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 48
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 226
def cop_line_ranges(analysis) analysis.close(Float::INFINITY) end
#cop_opted_in?(cop) ⇒ Boolean
# File 'lib/rubocop/comment_config.rb', line 58
def cop_opted_in?(cop) opt_in_cops.include?(cop.cop_name) end
#each_directive (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 230
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
#expand_cop_name(name) (private)
[ GitHub ]#extra_enabled_comments
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 66
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) # Push/pop and next-statement directives close themselves, so they # play no part in the disable/enable pairing. next if directive.push? || directive.pop? || directive.disable_next? 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 264
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 278
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 189
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 257
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,
used to mobilize cops disabled in the config on demand.
# File 'lib/rubocop/comment_config.rb', line 83
def opt_in_cops @opt_in_cops ||= begin cops = Set.new each_directive do |directive| next unless directive.enabled? next if directive.all_cops? cops.merge(directive.raw_cop_names) end cops end end
#pop_state(analyses, line) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 175
def pop_state(analyses, line) restore_point = @stack.pop (restore_point.keys | analyses.keys).each do |cop| analyses[cop] = popped_analysis(analyses[cop], restore_point[cop], line) end end
#popped_analysis(current, restored, line) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 182
def popped_analysis(current, restored, line) ranges = current.close(line - 1) return CopAnalysis.new(ranges, nil) unless restored&.start_line_number CopAnalysis.new(ranges, line, restored.start_directive) 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 252
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 239
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
#resolve_push_cops(directive) (private)
[ GitHub ]# File 'lib/rubocop/comment_config.rb', line 147
def resolve_push_cops(directive) directive.push_args.transform_values do |names| names.flat_map { |name| (name) } end end