nbadal / ktlint-intellij-plugin

Ktlint plugin for IntelliJ IDEA + Android Studio
MIT License
150 stars 22 forks source link

Current Dev plugin causes stack error #535

Closed ctdavids closed 3 weeks ago

ctdavids commented 3 weeks ago

Discovered this testing the solution for https://github.com/nbadal/ktlint-intellij-plugin/issues/527

The dev mode plugin produces this failure:

An error occurred while processing file 'C:/git/ktlintExample/lib/src/test/kotlin/org/example/AnotherTest.kt': java.lang.IllegalArgumentException: Stack should be empty: IndentContext(fromASTNode=Element(kotlin.FILE), toASTNode=PsiWhiteSpace, nodeIndent=, firstChildIndent=, childIndent=, lastChildIndent=, activated=true) IndentContext(fromASTNode=Element(CLASS), toASTNode=PsiElement(RBRACE), nodeIndent=, firstChildIndent=, childIndent=, lastChildIndent=, activated=false) IndentContext(fromASTNode=PsiElement(LBRACE), toASTNode=PsiElement(RBRACE), nodeIndent=, firstChildIndent=, childIndent= , lastChildIndent=, activated=true) IndentContext(fromASTNode=BLOCK, toASTNode=PsiElement(RBRACE), nodeIndent= , firstChildIndent= , childIndent= , lastChildIndent= , activated=false) IndentContext(fromASTNode=PsiElement(LBRACE), toASTNode=PsiElement(RBRACE), nodeIndent= , firstChildIndent=, childIndent= , lastChildIndent=, activated=true) at com.pinterest.ktlint.ruleset.standard.rules.IndentationRule.afterLastNode(IndentationRule.kt:1066) at com.pinterest.ktlint.rule.engine.internal.RuleExecutionContext.executeRule(RuleExecutionContext.kt:65) at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.executeRule(CodeFormatter.kt:116) at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format(CodeFormatter.kt:87) at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format(CodeFormatter.kt:56) at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format(CodeFormatter.kt:27) at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format$default(CodeFormatter.kt:19) at com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine.format(KtLintRuleEngine.kt:145) at com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine.format$default(KtLintRuleEngine.kt:139) at com.nbadal.ktlint.KtlintFormatKt.executeKtlint(KtlintFormat.kt:128) at com.nbadal.ktlint.KtlintFormatKt.ktlintFormat$lambda$0(KtlintFormat.kt:51) at com.intellij.openapi.command.WriteCommandAction.lambda$runWriteCommandAction$4(WriteCommandAction.java:338) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$doRunWriteCommandAction$1(WriteCommandAction.java:144) at com.intellij.openapi.application.impl.RwLockHolder.runWriteAction(RwLockHolder.kt:344) at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:883) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$doRunWriteCommandAction$2(WriteCommandAction.java:142) at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:216) at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:187) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.doRunWriteCommandAction(WriteCommandAction.java:151) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.run(WriteCommandAction.java:118) at com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction(WriteCommandAction.java:338) at com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction(WriteCommandAction.java:326) at com.nbadal.ktlint.KtlintFormatKt.ktlintFormat(KtlintFormat.kt:50) at com.nbadal.ktlint.KtlintPostFormatProcessor.processText(KtlintPostFormatProcessor.kt:21) at com.intellij.psi.impl.source.codeStyle.CoreCodeStyleUtil.postProcessRange(CoreCodeStyleUtil.java:147) at com.intellij.psi.impl.source.codeStyle.CoreCodeStyleUtil.postProcessEnabledRanges(CoreCodeStyleUtil.java:138) at com.intellij.psi.impl.source.codeStyle.CoreCodeStyleUtil.postProcessText(CoreCodeStyleUtil.java:126) at com.intellij.formatting.service.CoreFormattingService.lambda$formatRanges$5(CoreFormattingService.java:93) at com.intellij.psi.impl.source.codeStyle.CoreCodeStyleUtil.postProcessRanges(CoreCodeStyleUtil.java:114) at com.intellij.formatting.service.CoreFormattingService.formatRanges(CoreFormattingService.java:93) at com.intellij.formatting.service.FormattingServiceUtil.formatRanges(FormattingServiceUtil.java:117) at com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl.reformatText(CodeStyleManagerImpl.java:165) at com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl.reformatText(CodeStyleManagerImpl.java:91) at com.intellij.codeInsight.actions.ReformatCodeProcessor.doReformat(ReformatCodeProcessor.java:221) at com.intellij.codeInsight.actions.ReformatCodeProcessor.lambda$prepareTask$5(ReformatCodeProcessor.java:166) at com.intellij.psi.codeStyle.CodeStyleSettingsManager.runWithLocalSettings(CodeStyleSettingsManager.java:113) at com.intellij.application.options.CodeStyle.runWithLocalSettings(CodeStyle.java:366) at com.intellij.codeInsight.actions.ReformatCodeProcessor.lambda$prepareTask$6(ReformatCodeProcessor.java:158) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at com.intellij.codeInsight.actions.AbstractLayoutCodeProcessor$ProcessingTask.lambda$performFileProcessing$7(AbstractLayoutCodeProcessor.java:465) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$doRunWriteCommandAction$1(WriteCommandAction.java:144) at com.intellij.openapi.application.impl.RwLockHolder.runWriteAction(RwLockHolder.kt:344) at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:883) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$doRunWriteCommandAction$2(WriteCommandAction.java:142) at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:225) at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:187) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.doRunWriteCommandAction(WriteCommandAction.java:151) at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$run$0(WriteCommandAction.java:122) at com.intellij.util.concurrency.ContextRunnable.run(ContextRunnable.java:27) at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:209) at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:22) at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:191) at com.intellij.openapi.application.impl.RwLockHolder.runIntendedWriteActionOnCurrentThread(RwLockHolder.kt:204) at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:830) at com.intellij.openapi.application.impl.ApplicationImpl$2.run(ApplicationImpl.java:419) at com.intellij.openapi.application.impl.LaterInvocator$1.run(LaterInvocator.java:101) at com.intellij.openapi.application.impl.RwLockHolder.runWithEnabledImplicitRead(RwLockHolder.kt:138) at com.intellij.openapi.application.impl.RwLockHolder.runWithImplicitRead(RwLockHolder.kt:129) at com.intellij.openapi.application.impl.ApplicationImpl.runWithImplicitRead(ApplicationImpl.java:1152) at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:81) at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:123) at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:43) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792) at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739) at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:761) at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:699) at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$12(IdeEventQueue.kt:593) at com.intellij.openapi.application.impl.RwLockHolder.runWithoutImplicitRead(RwLockHolder.kt:105) at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:593) at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:77) at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:362) at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:361) at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:843) at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:361) at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:356) at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:1022) at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106) at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:1022) at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:356) at com.intellij.openapi.application.impl.RwLockHolder.runIntendedWriteActionOnCurrentThread(RwLockHolder.kt:209) at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:830) at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:398) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

when being asked to format:

package org.example

import io.foo.shouldBe
import kotlin.test.Test

class ThisFailsFormattingTest {
    @Test
    fun `performs expected cartesianProductIndexed`() {
        // @formatter:off
        A.mapIndexed { index, value ->
            "$index:$value"
        } shouldBe
            listOf(
                "0:x", "1:y", "2:z"
            )
        // @formatter:on
    }

    companion object {
        private val A = listOf("x", "y", "z")
    }
}

However oddly it does NOT fail when formatting the same thing, but with the infix function defined in the same file:

package org.example

import kotlin.test.Test
import kotlin.test.assertEquals

class ThisDoesNotFailFormattingTest {
    @Test
    fun `performs expected cartesianProductIndexed`() {
        // @formatter:off
        A.mapIndexed { index, value ->
            "$index:$value"
        } shouldBe
            listOf(
                "0:x", "1:y", "2:z"
            )
        // @formatter:on
    }

    infix fun Any?.shouldBe(expected: Any?) {
        assertEquals(expected, this)
    }

    companion object {
        private val A = listOf("x", "y", "z")
    }
}

Example project attached with the relevant files being in the test code and named as above.

ktlintExample.zip

paul-dingemans commented 3 weeks ago

You last code sample contains line below:

class ThisDoesNotFailFormattingTest {a

Note the last character on this line. Is this intentional?

ctdavids commented 3 weeks ago

No, it's not intentional and isn't required for the bug (nor is it present in the uploaded sample). Not sure how it got there. I'll edit it away.

ctdavids commented 3 weeks ago

So I have a guess as to what might be going on here. It might be running afoul of "standard:no-unused-imports" due to ignoring the contents inside the formatter off tags. I don't know why that would cause the stack trace (not that I've looked at its details), but it would explain the difference in behaviour between the "in the file" case and the "imported from elsewhere" case.

This may relate to ktlint 1.3.0 as well since version 23.0 of the plugin uses that by default which I don't believe was true with 22.0.

paul-dingemans commented 3 weeks ago

This problem does not seem to be caused by the ktlint-intellij-plugin but in ktlint itself. I can reproduce the exact same stacktrace, by malforming the "@formatter:on" tag:

$ ktlint-1.3.0 --stdin
08:03:08.208 [main] INFO com.pinterest.ktlint.cli.internal.KtlintCommandLine -- Enable default patterns [**/*.kt, **/*.kts]
fun foo123() {
    // @formatter:off
    listOf(
        "x" to 1, "x" to 2, "x" to 3,
        "x" to 1, "x" to 2, "x" to 3,
        "y" to 1, "y" to 2, "y" to 3,
        "z" to 1, "z" to 2, "z" to 3,
    )
    // The "@formatted:on" tag below is malformed on purpose.
    // It will cause an exception when indenting
    // @formstter:on
}

Exception in thread "main" java.lang.IllegalArgumentException: Stack should be empty:
        IndentContext(fromASTNode=Element(kotlin.FILE), toASTNode=PsiWhiteSpace, nodeIndent=, firstChildIndent=, childIndent=, lastChildIndent=, activated=true)
        IndentContext(fromASTNode=BLOCK, toASTNode=PsiElement(RBRACE), nodeIndent=, firstChildIndent=    , childIndent=    , lastChildIndent=    , activated=false)
        IndentContext(fromASTNode=PsiElement(LBRACE), toASTNode=PsiElement(RBRACE), nodeIndent=, firstChildIndent=, childIndent=    , lastChildIndent=, activated=true)
        at com.pinterest.ktlint.ruleset.standard.rules.IndentationRule.afterLastNode(IndentationRule.kt:1066)
        at com.pinterest.ktlint.rule.engine.internal.RuleExecutionContext.executeRule(RuleExecutionContext.kt:65)
        at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.executeRule(CodeFormatter.kt:116)
        at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format(CodeFormatter.kt:87)
        at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format(CodeFormatter.kt:56)
        at com.pinterest.ktlint.rule.engine.internal.CodeFormatter.format(CodeFormatter.kt:27)
        at com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine.lint(KtLintRuleEngine.kt:91)
        at com.pinterest.ktlint.cli.internal.KtlintCommandLine.lint(KtlintCommandLine.kt:558)
        at com.pinterest.ktlint.cli.internal.KtlintCommandLine.process(KtlintCommandLine.kt:466)
        at com.pinterest.ktlint.cli.internal.KtlintCommandLine.lintStdin(KtlintCommandLine.kt:425)
        at com.pinterest.ktlint.cli.internal.KtlintCommandLine.lintOrFormat(KtlintCommandLine.kt:296)
        at com.pinterest.ktlint.cli.internal.KtlintCommandLine.run(KtlintCommandLine.kt:246)
        at com.github.ajalt.clikt.parsers.Parser.finalizeAndRun(Parser.kt:348)
        at com.github.ajalt.clikt.parsers.Parser.parse(Parser.kt:218)
        at com.github.ajalt.clikt.parsers.Parser.parse(Parser.kt:42)
        at com.github.ajalt.clikt.core.CliktCommand.parse(CliktCommand.kt:457)
        at com.github.ajalt.clikt.core.CliktCommand.parse$default(CliktCommand.kt:454)
        at com.github.ajalt.clikt.core.CliktCommand.main(CliktCommand.kt:474)
        at com.github.ajalt.clikt.core.CliktCommand.main(CliktCommand.kt:481)
        at com.pinterest.ktlint.Main.main(Main.kt:20)
paul-dingemans commented 3 weeks ago

This may relate to ktlint 1.3.0 as well since version 23.0 of the plugin uses that by default which I don't believe was true with 22.0.

Indeed, with ktlint 1.2.1 above problem does not occur.

paul-dingemans commented 3 weeks ago

I will close this issue, and resolve it in ktlint 1.3.1 (https://github.com/pinterest/ktlint/issues/2695).

ctdavids commented 3 weeks ago

Great thanks. I found a workaround as well which was to have at least one test that relied on the import and was NOT inside the formatter tags (thus meaning there was no unused import). For some reason this avoided the failure.

paul-dingemans commented 3 weeks ago

Great thanks. I found a workaround as well which was to have at least one test that relied on the import and was NOT inside the formatter tags (thus meaning there was no unused import). For some reason this avoided the failure.

Actually, you just found another bug in ktlint. Tnx!

ctdavids commented 3 weeks ago

Appreciate your rapid responses!