afnanenayet / diffsitter

A tree-sitter based AST difftool to get meaningful semantic diffs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Out of bounds index diffing Go code

ekilmer opened this issue · comments

Describe the bug
I get an out of bounds index error when diffing Go code:

thread 'main' panicked at 'byte index 6 is out of bounds of `   do()`', src/formatting.rs:403:43

To Reproduce

Have a file a.go:

package main

import "fmt"

func main() {
	b := "string"
	fmt.Println(b)
	c := "hi"
	fmt.Println(c)
}

Have a file b.go:

package main

import "fmt"

func main() {
	do()
}

func do() {
	b := "string"
	fmt.Println(b)
	c := "hi"
	fmt.Println(c)
}

Run the following to see the error:

$ env RUST_BACKTRACE=1 cargo run --package diffsitter --bin diffsitter a.go b.go
   Compiling diffsitter v0.7.1 (/Users/ekilmer/src/diffsitter)
    Finished dev [unoptimized + debuginfo] target(s) in 1.44s
     Running `target/debug/diffsitter a.go b.go`
thread 'main' panicked at 'byte index 6 is out of bounds of `   do()`', src/formatting.rs:403:43
stack backtrace:
   0: rust_begin_unwind
             at /rustc/0da281b6068a7d889ae89a9bd8991284cc9b7535/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/0da281b6068a7d889ae89a9bd8991284cc9b7535/library/core/src/panicking.rs:65:14
   2: core::str::slice_error_fail_rt
   3: core::str::slice_error_fail
             at /rustc/0da281b6068a7d889ae89a9bd8991284cc9b7535/library/core/src/str/mod.rs:86:9
   4: core::str::traits::<impl core::slice::index::SliceIndex<str> for core::ops::range::Range<usize>>::index
             at /rustc/0da281b6068a7d889ae89a9bd8991284cc9b7535/library/core/src/str/traits.rs:218:21
   5: core::str::traits::<impl core::ops::index::Index<I> for str>::index
             at /rustc/0da281b6068a7d889ae89a9bd8991284cc9b7535/library/core/src/str/traits.rs:65:9
   6: diffsitter::formatting::DiffWriter::print_line
             at ./src/formatting.rs:403:43
   7: diffsitter::formatting::DiffWriter::print_hunk
             at ./src/formatting.rs:354:13
   8: diffsitter::formatting::DiffWriter::print
             at ./src/formatting.rs:227:21
   9: diffsitter::run_diff
             at ./src/main.rs:182:5
  10: diffsitter::main
             at ./src/main.rs:275:13
  11: core::ops::function::FnOnce::call_once
             at /rustc/0da281b6068a7d889ae89a9bd8991284cc9b7535/library/core/src/ops/function.rs:251:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
a.go -> b.go
============

5 - 8:
------
+       do()

Expected behavior
I expect no error and a diff.

Log output/screenshots
See above

Platform:
OS: macOS 13.0
Rust: rustc 1.66.0-nightly (0da281b60 2022-10-27)

Additional context
I was able to debug and make a patch that allows the tool to finish without crashing. I'm not very familiar with Rust or this project, so this patch could probably use some improvement.

Patch:

diff --git a/src/formatting.rs b/src/formatting.rs
index 00d822b..f5077cf 100644
--- a/src/formatting.rs
+++ b/src/formatting.rs
@@ -388,6 +388,9 @@ fn print_line(
 
         // We keep printing ranges until we've covered the entire line
         for entry in &line.entries {
+            if entry.text.eq_ignore_ascii_case("\n") || entry.text.eq_ignore_ascii_case("\r") {
+                continue;
+            }
             // The range of text to emphasize
             // TODO(afnan) deal with ranges spanning multiple rows
             let emphasis_range = entry.start_position().column..entry.end_position().column;

Output with patch:

$ cargo run --package diffsitter --bin diffsitter a.go b.go
    Finished dev [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/diffsitter a.go b.go`
a.go -> b.go
============

5 - 8:
------
+       do()
+ }
+
+ func do() {

Interesting, it seems like the tree-sitter parser for go counts each newline as a node