Skip to content

Commit

Permalink
[Fix #7900] Fix Style/FormatStringToken false positive with formatt…
Browse files Browse the repository at this point in the history
…ed input and `template` style enforced, and add autocorrection
  • Loading branch information
FnControlOption authored and bbatsov committed Jun 23, 2022
1 parent 08833f9 commit 8eb4f1b
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 72 deletions.
@@ -0,0 +1 @@
* [#7900](https://github.com/rubocop/rubocop/issues/7900): Fix `Style/FormatStringToken` false positive with formatted input and `template` style enforced, and add autocorrection. ([@FnControlOption][])
65 changes: 48 additions & 17 deletions lib/rubocop/cop/style/format_string_token.rb
Expand Up @@ -69,6 +69,7 @@ module Style
class FormatStringToken < Base
include ConfigurableEnforcedStyle
include IgnoredMethods
extend AutoCorrector

def on_str(node)
return if format_string_token?(node) || use_ignored_method?(node)
Expand All @@ -77,13 +78,8 @@ def on_str(node)
return if detections.empty?
return if allowed_unannotated?(detections)

detections.each do |detected_style, token_range|
if detected_style == style
correct_style_detected
else
style_detected(detected_style)
add_offense(token_range, message: message(detected_style))
end
detections.each do |detected_sequence, token_range|
check_sequence(detected_sequence, token_range)
end
end

Expand All @@ -106,6 +102,38 @@ def use_ignored_method?(node)
send_parent && ignored_method?(send_parent.method_name)
end

def check_sequence(detected_sequence, token_range)
if detected_sequence.style == style
correct_style_detected
elsif correctable_sequence?(detected_sequence.type)
style_detected(detected_sequence.style)
add_offense(token_range, message: message(detected_sequence.style)) do |corrector|
autocorrect_sequence(corrector, detected_sequence, token_range)
end
end
end

def correctable_sequence?(detected_type)
detected_type == 's' || style == :annotated || style == :unannotated
end

def autocorrect_sequence(corrector, detected_sequence, token_range)
return if style == :unannotated

name = detected_sequence.name
return if name.nil?

flags = detected_sequence.flags
width = detected_sequence.width
precision = detected_sequence.precision
type = detected_sequence.style == :template ? 's' : detected_sequence.type
correction = case style
when :annotated then "%<#{name}>#{flags}#{width}#{precision}#{type}"
when :template then "%#{flags}#{width}#{precision}{#{name}}"
end
corrector.replace(token_range, correction)
end

def unannotated_format?(node, detected_style)
detected_style == :unannotated && !format_string_in_typical_context?(node)
end
Expand Down Expand Up @@ -143,30 +171,33 @@ def str_contents(source_map)
def token_ranges(contents)
format_string = RuboCop::Cop::Utils::FormatString.new(contents.source)

format_string.format_sequences.each do |seq|
next if seq.percent?
format_string.format_sequences.each do |detected_sequence|
next if detected_sequence.percent?

detected_style = seq.style
token = contents.begin.adjust(begin_pos: seq.begin_pos, end_pos: seq.end_pos)
token = contents.begin.adjust(begin_pos: detected_sequence.begin_pos,
end_pos: detected_sequence.end_pos)

yield(detected_style, token)
yield(detected_sequence, token)
end
end

def collect_detections(node)
detections = []
tokens(node) do |detected_style, token_range|
unless unannotated_format?(node, detected_style)
detections << [detected_style, token_range]
tokens(node) do |detected_sequence, token_range|
unless unannotated_format?(node, detected_sequence.style)
detections << [detected_sequence, token_range]
end
end
detections
end

def allowed_unannotated?(detections)
return false if detections.size > max_unannotated_placeholders_allowed
return false unless detections.all? do |detected_sequence,|
detected_sequence.style == :unannotated
end
return true if detections.size <= max_unannotated_placeholders_allowed

detections.all? { |detected_style,| detected_style == :unannotated }
detections.any? { |detected_sequence,| !correctable_sequence?(detected_sequence.type) }
end

def max_unannotated_placeholders_allowed
Expand Down

0 comments on commit 8eb4f1b

Please sign in to comment.