I’m working on upgrading the IntelliJ Elixir plugin to support 2025.2.1+, and have found a really weird bug that didn’t exist before, with regards to Usages.
java.lang.IllegalArgumentException: Comparison method violates its general contract! in UsageViewImpl.syncModelWithSwingNodes() due to how the comparator is implemented in GroupNode.NodeComparator.
It seems to happen with bulk usage operations, particularly in plugin tests.
What I understand..
(Current IntelliJ 2025.2.1 release, this has recently changed…):
// Line 305 in NodeComparator.compare() - IntelliJ 2025.2.1
return System.identityHashCode(u1) - System.identityHashCode(u2); // VIOLATION
Stack Trace
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.base/java.util.TimSort.mergeHi(TimSort.java:903)
at java.base/java.util.TimSort.mergeAt(TimSort.java:520)
at java.base/java.util.TimSort.mergeForceCollapse(TimSort.java:461)
at java.base/java.util.TimSort.sort(TimSort.java:254)
at java.base/java.util.Arrays.sort(Arrays.java:1308)
at java.base/java.util.Vector.sort(Vector.java:1385)
at com.intellij.usages.impl.UsageViewImpl.syncModelWithSwingNodes(UsageViewImpl.java:589)
at com.intellij.usages.impl.UsageViewImpl.fireEvents(UsageViewImpl.java:497)
How to reproduce
# Clone intellij-elixir plugin (feature/kotlin-220 branch)
git clone https://github.com/KronicDeth/intellij-elixir
cd intellij-elixir
git checkout feature/kotlin-220
# Run find usages tests - 11/22 fail with comparator violation
./gradlew test --tests "org.elixir_lang.FindUsagesTest"
Multiple tests fail with identical stack trace at UsageViewImpl.syncModelWithSwingNodes:589
Workarounds?
Not sure how to proceed from here, I’m considering just ignoring the test for now, and seeing how many users have issues?
This job shows different errors from the Elixir PSI implementation where smart pointer can’t be restored immediately after its creation.
2025-08-08T14:37:38.5364888Z Caused by: com.intellij.testFramework.TestLoggerFactory$TestLoggerAssertionError: Cannot restore UNMATCHED_UNQUALIFIED_NO_PARENTHESES_CALL of class org.elixir_lang.psi.impl.ElixirUnmatchedUnqualifiedNoParenthesesCallImpl from injected{type=Identikit(class='org.elixir_lang.psi.impl.ElixirUnmatchedUnqualifiedNoParenthesesCallImpl', elementType=UNMATCHED_UNQUALIFIED_NO_PARENTHESES_CALL, fileLanguage='Elixir'), range=SmartPsiFileRangePointerImpl{psi:range=(11810,11898),type=Identikit(class='com.intellij.psi.PsiElement', elementType=-1, fileLanguage='')}, host=psi:range=(11591,12989),type=Identikit(class='org.elixir_lang.psi.impl.ElixirLiteralSigilHeredocImpl', elementType=LITERAL_SIGIL_HEREDOC, fileLanguage='Elixir')}; restored=null in Project(name=ModuleNestedRecursiveDeclaration, containerState=COMPONENT_CREATED, componentStore=/tmp/unitTest_functionRecursiveUsage_310bFFksLSWs8g7ZQAjNtPoeuNo/light_temp_310bFNTYknSqqbpbXFU4rVtRSzr.ipr)
2025-08-08T14:37:38.5371725Z at com.intellij.testFramework.TestLoggerFactory$TestLogger.error(TestLoggerFactory.java:457)
2025-08-08T14:37:38.5373253Z at com.intellij.openapi.diagnostic.Logger.error(Logger.java:375)
2025-08-08T14:37:38.5379403Z at com.intellij.psi.impl.smartPointers.SmartPsiElementPointerImpl.createElementInfo(SmartPsiElementPointerImpl.java:153)
2025-08-08T14:37:38.5381269Z at com.intellij.psi.impl.smartPointers.SmartPsiElementPointerImpl.<init>(SmartPsiElementPointerImpl.java:48)