bnorm/kotlin-power-assert

StringIndexOutOfBoundsException in IrStackVariableKt.buildMessage

Closed this issue · 8 comments

Trying a simple test with the following code:

import kotlin.test.*

class TestTest {
    @Test
    fun testFails() {
        val a = 0
        assertTrue(a == 42)
    }
}

Getting the following exception during build:

e: java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 7
	at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3319)
	at java.base/java.lang.String.substring(String.java:1874)
	at com.bnorm.power.IrStackVariableKt.buildMessage(IrStackVariable.kt:85)
	at com.bnorm.power.PowerAssertCallTransformer$visitCall$$inlined$run$lambda$1.buildAssertThrow(PowerAssertCallTransformer.kt:128)
	at com.bnorm.power.PowerAssertGenerator$buildAssert$$inlined$irBlock$lambda$1.invoke(PowerAssertGenerator.kt:41)
	at com.bnorm.power.PowerAssertGenerator$buildAssert$$inlined$irBlock$lambda$1.invoke(PowerAssertGenerator.kt:32)
	at com.bnorm.power.PowerAssertGenerator.buildAssert(PowerAssertGenerator.kt:123)
	at com.bnorm.power.PowerAssertGenerator.buildAssert(PowerAssertGenerator.kt:40)
	at com.bnorm.power.PowerAssertCallTransformer.visitCall(PowerAssertCallTransformer.kt:138)
	at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitCall(IrElementTransformerVoid.kt:173)
...

Full project can be found here: https://github.com/elizarov/KotlinPowerAssertPlayground

bnorm commented

Thanks for the ticket! Unfortunately I've been unable to reproduce even using your project. Is there anything unique about your setup that comes to mind?

While I cannot be 100% confident, breadcrumbs from the stacktrace and the example which is failing leads me to guess it is failing to find the == characters in the string a == 42. The way equality and comparison operators are found in an expression is very sub-optimal and I have been unable to find an alternative to just searching for the strings ==, !=, <=, etc.

I will work on cleaning up this area of the plugin but it would still be interesting to determine the root cause in case there needs to be something added to the README.

Tested it more. It fails only on Windows. Works fine on my MacOS. It might have something to do with platform-specific line terminator (two bytes CRLF on Windows).

bnorm commented

That's odd, because while originally I tried to reproduce on MacOS Laptop, I develop this library primarily on a Windows desktop. I quickly cloned the project there as well and was still unable to reproduce. I wonder if git is hiding an issue? Or if default IntelliJ import is hiding something?

Fails for me on Windows with gradlew clean build from the command line.

Maybe your windows git is configured to checkout with unix-style one-byte line-separators? That's the only thing coming to my mind that could matter.

bnorm commented

That was indeed it! Thanks for the assistance!

Hmm... This is rather odd. It appears the startOffset and endOffset values of an IrExpression assume that the file text has had \r removed. Currently I'm reading the file text as File(irFile.path).readText() but that appears to be inconsistent with how the IrExpression offsets are calculated.

Firstly, it's trivial to add a .replace("\r", "") to get this library working with files that have Windows-style line-separators. I'll get that fix pushed out soon.

Secondly, it seems the plugin needs to better coordinate with the compiler what the text of the file is. I'm not aware of any way to get the text of the file directly from the compiler which is why I read the file myself. If the compiler is not going to provide access to its representation of the file text, I think it needs to maintain the offsets without modifications to the raw text of the file. As such, I think there are 3 different ways this situation can go:

  1. There is already a way to get the file text from the compiler and I'm just unaware.
  2. The compiler needs to provide access to its representation of the file text.
  3. The compiler needs to make the startOffset and endOffset of an IrExpression match the raw text of the file.

I'll create a ticket against the compiler and link it here for tracking.

bnorm commented

I've created https://youtrack.jetbrains.com/issue/KT-41888 for the Kotlin compiler.

bnorm commented

Released version 0.5.1 which includes a fix.