IncorrectOperationException: Must not modify PSI inside save listener

Hi,

I am developing a plugin for IntelliJ that adds the "final" modifier to all method parameters, if it does not exist, just prior to the file being saved.  I tested this with IntelliJ v11 and was able to get it working successfully.  However, when I took the same code and put it into my plugin to be used with IntelliJ v14, I received the following exception:

[  24087]  ERROR - .impl.MessageBusConnectionImpl - IntelliJ IDEA 14.0.2  Build #IC-139.659.2 [  24087]  ERROR - .impl.MessageBusConnectionImpl - JDK: 1.6.0_65 [  24087]  ERROR - .impl.MessageBusConnectionImpl - VM: Java HotSpot(TM) 64-Bit Server VM [  24087]  ERROR - .impl.MessageBusConnectionImpl - Vendor: Apple Inc. [  24087]  ERROR - .impl.MessageBusConnectionImpl - OS: Mac OS X [  24087]  ERROR - .impl.MessageBusConnectionImpl - Last Action: SaveAll [  29180]  ERROR - .impl.MessageBusConnectionImpl - Must not modify PSI inside save listener com.intellij.util.IncorrectOperationException: Must not modify PSI inside save listener      at com.intellij.pom.core.impl.PomModelImpl.runTransaction(PomModelImpl.java:138)      at com.intellij.psi.impl.source.tree.ChangeUtil.prepareAndRunChangeAction(ChangeUtil.java:165)      at com.intellij.psi.impl.source.tree.CompositeElement.removeChildrenInner(CompositeElement.java:937)      at com.intellij.psi.impl.source.tree.CompositeElement.addChild(CompositeElement.java:652)      at com.intellij.psi.impl.source.tree.CompositeElement.addChildren(CompositeElement.java:761)      at com.intellij.psi.impl.source.codeStyle.CodeEditUtil.addChildren(CodeEditUtil.java:82)      at com.intellij.psi.impl.source.tree.CompositeElement.addInternal(CompositeElement.java:540)      at com.intellij.psi.impl.source.tree.java.ModifierListElement.addInternal(ModifierListElement.java:45)      at com.intellij.psi.impl.source.PsiModifierListImpl.setModifierProperty(PsiModifierListImpl.java:230)      at com.arvatosystems.us.saveActions.BeforeSaveComponent$2.run(BeforeSaveComponent.java:114)      at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:124)      at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:99)      at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:85)      at com.arvatosystems.us.saveActions.BeforeSaveComponent.applyFinalToMethodParameters(BeforeSaveComponent.java:109)      at com.arvatosystems.us.saveActions.BeforeSaveComponent.access$000(BeforeSaveComponent.java:23)      at com.arvatosystems.us.saveActions.BeforeSaveComponent$1.beforeDocumentSaving(BeforeSaveComponent.java:54)      at sun.reflect.GeneratedMethodAccessor110.invoke(Unknown Source)      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)      at java.lang.reflect.Method.invoke(Method.java:597)      at com.intellij.util.messages.impl.MessageBusConnectionImpl.deliverMessage(MessageBusConnectionImpl.java:114)      at com.intellij.util.messages.impl.MessageBusImpl.doPumpMessages(MessageBusImpl.java:315)      at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:302)      at com.intellij.util.messages.impl.MessageBusImpl.sendMessage(MessageBusImpl.java:287)      at com.intellij.util.messages.impl.MessageBusImpl.access$200(MessageBusImpl.java:41)      at com.intellij.util.messages.impl.MessageBusImpl$2.invoke(MessageBusImpl.java:177)      at com.sun.proxy.$Proxy20.beforeDocumentSaving(Unknown Source)      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)      at java.lang.reflect.Method.invoke(Method.java:597)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.multiCast(FileDocumentManagerImpl.java:128)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.access$000(FileDocumentManagerImpl.java:87)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl$1.invoke(FileDocumentManagerImpl.java:116)      at com.sun.proxy.$Proxy20.beforeDocumentSaving(Unknown Source)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl$4.run(FileDocumentManagerImpl.java:411)      at com.intellij.pom.core.impl.PomModelImpl.guardPsiModificationsIn(PomModelImpl.java:354)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.doSaveDocumentInWriteAction(FileDocumentManagerImpl.java:408)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.doSaveDocument(FileDocumentManagerImpl.java:382)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveAllDocuments(FileDocumentManagerImpl.java:303)      at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveAllDocuments(FileDocumentManagerImpl.java:282)      at com.intellij.openapi.application.impl.ApplicationImpl.saveAll(ApplicationImpl.java:1449)      at com.intellij.ide.actions.SaveAllAction.actionPerformed(SaveAllAction.java:26)      at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher$3.performAction(IdeKeyEventDispatcher.java:614)      at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:663)      at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.inInitState(IdeKeyEventDispatcher.java:513)      at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.java:211)      at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:546)      at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:384)      at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)      at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)      at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)      at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


The reason that I'm receiving this exception is fairly obvious (I am indeed modifying a PSI element in the FileDocumentManagerAdapter.beforeDocumentSaving() method).  However, I don't understand why this is no longer allowed, and more importantly, how I can resolve this exception.  What is the suggested approach for building a plugin of this type to be compatible with IntelliJ v14?

Thanks,
Eric

4 comments
Comment actions Permalink

I guess it's up to JetBrains team to answer some of your questions.

In the meantime, I could suggest trying

ApplicationManager.getApplication().runWriteAction()


This might solve the writting issue (though I suspect it won't write at the time you want... maybe trigger another save after writting?)

0
Comment actions Permalink

Hi Jonathan,

Thank you for the suggestion, but this was actually the first thing I tried.  I still ended up receiving the same exception.

To the IntelliJ team -  I see that a couple of other people have run into the same issue with their plugins, i.e.:
https://github.com/editorconfig/editorconfig/issues/161
https://github.com/antlr/intellij-plugin-v4/issues/151

Unfortunately, no solution was posted for either of these two issues.  Could you please assist me in rectifying this problem?

Thank you,
Eric

0
Comment actions Permalink

Hi Eric,
The reason of this exception is maintaining integrity of IDEA internal indices:
since during the PSI modification the document also needs to be changed, and we are aleady saving the document, some serious discrepancies may occur.
As a workaround, you can e.g. postpone the modification via

ApplicationManager.getApplication().invokeLater(new Runnable() {
  @Override
  public void
run() {
    doModification();
  }
}, myProject.getDisposed());
0
Comment actions Permalink

Hi Alexey,

Thank you for the explanation.  I arrived at the same workaround, which seems kind of hacky, but it does manage to resolve the exception.

Thanks,
Eric

0

Please sign in to leave a comment.