lib/rubocop/comment_config.rb in rubocop-0.40.0 vs lib/rubocop/comment_config.rb in rubocop-0.41.0
- old
+ new
@@ -4,81 +4,134 @@
module RuboCop
# 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.
class CommentConfig
UNNEEDED_DISABLE = 'Lint/UnneededDisable'.freeze
+
+ COP_NAME_PATTERN = '([A-Z][a-z]+/)?(?:[A-Z][a-z]+)+'.freeze
+ COP_NAMES_PATTERN = "(?:#{COP_NAME_PATTERN} , )*#{COP_NAME_PATTERN}".freeze
+ COPS_PATTERN = "(all|#{COP_NAMES_PATTERN})".freeze
+
COMMENT_DIRECTIVE_REGEXP = Regexp.new(
- '\A# rubocop : ((?:dis|en)able)\b ((?:[\w/]+,? )+)'.gsub(' ', '\s*')
+ ('\A# rubocop : ((?:dis|en)able)\b ' + COPS_PATTERN).gsub(' ', '\s*')
)
+ CopAnalysis = Struct.new(:line_ranges, :start_line_number)
+
attr_reader :processed_source
def initialize(processed_source)
@processed_source = processed_source
end
def cop_enabled_at_line?(cop, line_number)
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? { |range| range.include?(line_number) }
end
def cop_disabled_line_ranges
@cop_disabled_line_ranges ||= analyze
end
private
def analyze
- disabled_line_ranges = Hash.new { |hash, key| hash[key] = [] }
- disablement_start_line_numbers = {}
+ analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
each_mentioned_cop do |cop_name, disabled, line, single_line|
- if single_line
- disabled_line_ranges[cop_name] << (line..line) if disabled
- elsif disabled
- if disablement_start_line_numbers[cop_name]
- # Cop already disabled on this line, so we end the current disabled
- # range before we start a new range.
- start_line = disablement_start_line_numbers.delete(cop_name)
- disabled_line_ranges[cop_name] << (start_line..line)
- end
- disablement_start_line_numbers[cop_name] = line
- else
- start_line = disablement_start_line_numbers.delete(cop_name)
- disabled_line_ranges[cop_name] << (start_line..line) if start_line
- end
+ analyses[cop_name] =
+ analyze_cop(analyses[cop_name], disabled, line, single_line)
end
- disablement_start_line_numbers.each do |cop_name, start_line|
- disabled_line_ranges[cop_name] << (start_line..Float::INFINITY)
+ analyses.each_with_object({}) do |element, hash|
+ cop_name, analysis = *element
+ hash[cop_name] = cop_line_ranges(analysis)
end
+ end
- disabled_line_ranges
+ def analyze_cop(analysis, disabled, line, single_line)
+ if single_line
+ analyze_single_line(analysis, line, disabled)
+ elsif disabled
+ analyze_disabled(analysis, line)
+ else
+ analyze_rest(analysis, line)
+ end
end
- def each_mentioned_cop
- return if processed_source.comments.nil?
+ def analyze_single_line(analysis, line, disabled)
+ return analysis unless disabled
- processed_source.comments.each do |comment|
- match = comment.text.match(COMMENT_DIRECTIVE_REGEXP)
- next unless match
+ CopAnalysis.new(analysis.line_ranges + [(line..line)],
+ analysis.start_line_number)
+ end
- switch, cops_string = match.captures
+ def analyze_disabled(analysis, line)
+ if (start_line = analysis.start_line_number)
+ # Cop already disabled on this line, so we end the current disabled
+ # range before we start a new range.
+ return CopAnalysis.new(analysis.line_ranges + [start_line..line], line)
+ end
- cop_names =
- cops_string == 'all' ? all_cop_names : cops_string.split(/,\s*/)
+ CopAnalysis.new(analysis.line_ranges, line)
+ end
- disabled = (switch == 'disable')
+ def analyze_rest(analysis, line)
+ if (start_line = analysis.start_line_number)
+ return CopAnalysis.new(analysis.line_ranges + [start_line..line], nil)
+ end
+
+ CopAnalysis.new(analysis.line_ranges, nil)
+ end
+
+ def cop_line_ranges(analysis)
+ return analysis.line_ranges unless analysis.start_line_number
+
+ analysis.line_ranges + [(analysis.start_line_number..Float::INFINITY)]
+ end
+
+ def each_mentioned_cop
+ each_directive do |comment, cop_names, disabled|
comment_line_number = comment.loc.expression.line
single_line = !comment_only_line?(comment_line_number)
cop_names.each do |cop_name|
- cop_name = Cop::Cop.qualified_cop_name(cop_name.strip,
- processed_source.buffer.name)
- yield cop_name, disabled, comment_line_number, single_line
+ yield qualified_cop_name(cop_name), disabled, comment_line_number,
+ single_line
end
end
+ end
+
+ def each_directive
+ return if processed_source.comments.nil?
+
+ processed_source.comments.each do |comment|
+ directive = directive_parts(comment)
+ next unless directive
+
+ yield comment, *directive
+ end
+ end
+
+ def directive_parts(comment)
+ match = comment.text.match(COMMENT_DIRECTIVE_REGEXP)
+ return unless match
+
+ switch, cops_string = match.captures
+
+ cop_names =
+ cops_string == 'all' ? all_cop_names : cops_string.split(/,\s*/)
+
+ disabled = (switch == 'disable')
+
+ [cop_names, disabled]
+ end
+
+ def qualified_cop_name(cop_name)
+ Cop::Cop.qualified_cop_name(cop_name.strip, processed_source.buffer.name)
end
def all_cop_names
@all_cop_names ||= Cop::Cop.all.map(&:cop_name).reject do |cop_name|
cop_name == UNNEEDED_DISABLE