Skip to content

Commit

Permalink
Merge pull request #7202 from buehmann/tab/4719
Browse files Browse the repository at this point in the history
[Fix #4719] Detect tabs between string literals
  • Loading branch information
koic committed Jul 13, 2019
2 parents 640940f + 33d0f3b commit 3c70aad
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@
* [#7186](https://github.com/rubocop-hq/rubocop/issues/7186): Fix a false positive for `Style/MixinUsage` when using inside multiline block and `if` condition is after `include`. ([@koic][])
* [#7099](https://github.com/rubocop-hq/rubocop/issues/7099): Fix an error of `Layout/RescueEnsureAlignment` on assigned blocks. ([@tatsuyafw][])
* [#5088](https://github.com/rubocop-hq/rubocop/issues/5088): Fix an error of `Layout/MultilineMethodCallIndentation` on method chains inside an argument. ([@buehmann][])
* [#4719](https://github.com/rubocop-hq/rubocop/issues/4719): Make `Layout/Tab` detect tabs between string literals. ([@buehmann][])

### Changes

Expand Down
32 changes: 10 additions & 22 deletions lib/rubocop/cop/layout/tab.rb
Expand Up @@ -30,16 +30,13 @@ def investigate(processed_source)
str_ranges = string_literal_ranges(processed_source.ast)

processed_source.lines.each.with_index(1) do |line, lineno|
match = line.match(/^([^\t]*)\t+/)
match = line.match(/\t+/)
next unless match

prefix = match.captures[0]
col = prefix.length
next if in_string_literal?(str_ranges, lineno, col)

range = source_range(processed_source.buffer,
lineno,
col...match.end(0))
match.begin(0)...match.end(0))
next if in_string_literal?(str_ranges, range)

add_offense(range, location: range)
end
Expand All @@ -54,16 +51,9 @@ def autocorrect(range)

private

# rubocop:disable Metrics/CyclomaticComplexity
def in_string_literal?(ranges, line, col)
ranges.any? do |range|
(range.line == line && range.column <= col) ||
(range.line < line && line < range.last_line) ||
(range.line != line && range.last_line == line &&
range.last_column >= col)
end
def in_string_literal?(ranges, tabs_range)
ranges.any? { |range| range.contains?(tabs_range) }
end
# rubocop:enable Metrics/CyclomaticComplexity

def string_literal_ranges(ast)
# which lines start inside a string literal?
Expand All @@ -72,13 +62,11 @@ def string_literal_ranges(ast)
ast.each_node(:str, :dstr).each_with_object(Set.new) do |str, ranges|
loc = str.location

range = if str.heredoc?
loc.heredoc_body
else
loc.expression
end

ranges << range
if str.heredoc?
ranges << loc.heredoc_body
elsif loc.respond_to?(:begin) && loc.begin
ranges << loc.expression
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions spec/rubocop/cop/layout/tab_spec.rb
Expand Up @@ -44,6 +44,13 @@
RUBY
end

it 'registers an offense for tabs between string literals' do
expect_offense(<<~RUBY)
'foo'\t'bar'
^ Tab detected.
RUBY
end

it 'accepts a line with tab in a string' do
expect_no_offenses("(x = \"\t\")")
end
Expand Down

0 comments on commit 3c70aad

Please sign in to comment.