Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullPointerException when Ktlint runs the rule multiline-expression-wrapping during formatting #2297

Closed
Nenrikido opened this issue Oct 9, 2023 · 2 comments · Fixed by #2300

Comments

@Nenrikido
Copy link

Expected Behavior

The rule should at least pass without errors and tell me if there are linting issues or not

Observed Behavior

When running the command mvn antrun:run@ktlint-format with this configuration in the pom.xml :

<configuration>
    <target name="ktlint">
        <java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
              classpathref="maven.plugin.classpath" classname="com.pinterest.ktlint.Main">
            <arg value="-F"/>
            <arg value="src/**/*.kt"/>
            <arg value="!src/**/test/**"/>
            <arg value="--disabled_rules=enum-entry-name-case,function-naming,no-consecutive-comments,comment-wrapping,package-name,no-empty-file,property-naming,filename"/>
        </java>
    </target>
</configuration>

I'm getting the error :

Internal Error (rule 'standard:multiline-expression-wrapping') in DataFrameImpl.kt at position '0:0. Please create a ticket at https://github.com/pinterest/ktlint/issues and provide the source code that triggered an error.        
[INFO]    [ktlint] com.pinterest.ktlint.rule.engine.api.KtLintRuleException: Rule 'standard:multiline-expression-wrapping' throws exception in file 'DataFrameImpl.kt' at position (0:0)
...
Caused by: java.lang.NullPointerException
[INFO]    [ktlint]      at com.pinterest.ktlint.ruleset.standard.rules.MultilineExpressionWrappingRule.isElvisOperator(MultilineExpressionWrappingRule.kt:155)
...

(I copy-pasted the interesting parts of the stack trace but if you want the full stack-trace, please tell me)

Steps to Reproduce

I'm linking to this issue 2 files where the exception arises at position 0:0, since i don't know where the bug comes from exactly in the files, I can't reduce the size of the code sample. Sorry for that
KtFilesWithError.zip

My Environment

  • Version of ktlint used:
    1.0.0
  • Name and version (or code for custom task) of integration used (Gradle plugin, Maven plugin, command line, custom Gradle task):
    • Java version : 11.0.2
    • Maven version : 3.8.7
    • Plugin used for execution : org.apache.maven.plugins:maven-antrun-plugin:3.1.0
  • Operating System and version:
    Windows 11 Professional Version 10.0.22621 Build 22621
@paul-dingemans
Copy link
Collaborator

The problematic statement is following:

        return columns.size == otherColumns.size
                && columns.all { col ->
            val otherCol = otherColumns.firstOrNull { c -> c.name() == col.name() } ?: return@all false
            val result = col == otherCol
            if (!result) {
                println("column this[${col.name()}] != other[${otherCol.name()}]")
                println("this =\n${col}")
                println("other =\n${otherCol}")
            }
            result
        }

and specifically, the line starting with &&. The problem is caused by the chain-wrapping rule merges the && with the previous line, but malforms the AST while doing so. Because of the malformed AST, the MultilineExpressionWrappingRule throws a nullpointer exception.

Change your code as follows to work around this problem for now:

    override fun equals(other: Any?): Boolean {
        val df = other as? DataFrame ?: return false
        val otherColumns = df.columns()
        return columns.size ==
                otherColumns.size &&
                columns.all { col ->
            val otherCol = otherColumns.firstOrNull { c -> c.name() == col.name() } ?: return@all false
            val result = col == otherCol
            if (!result) {
                println("column this[${col.name()}] != other[${otherCol.name()}]")
                println("this =\n${col}")
                println("other =\n${otherCol}")
            }
            result
        }
    }

The problem above can be reproduced with simplified example:

            fun foo(): Boolean {
                return true
                        &&
                    columns.all { col ->
                        false
                    }
            }

@Nenrikido
Copy link
Author

Thanks for the quick answer, the insights, and the workaround. I will apply it in waiting for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants