apache / apache/netbeans

Wrong if condition in LSP applyEditsNoLock()

Open
#4,645 0 comments 0 reactions 0 assignees View on GitHub
kind:bug LSP needs:triage
Dominant language
Java
Stars
3.1k
Forks
935
Avg merge
2d 3h
Merged PRs (30d)
17

Description

### Apache NetBeans version

Apache NetBeans 15

### What happened
```
java.lang.IllegalArgumentException: len=-1 < 0
at org.netbeans.editor.BaseDocument.handleRemove(BaseDocument.java:949)
at org.netbeans.editor.BaseDocument$FilterBypassImpl.remove(BaseDocument.java:2639)
at java.desktop/javax.swing.text.DocumentFilter.remove(DocumentFilter.java:79)
at org.openide.text.CloneableEditorSupport$DocFilter.remove(CloneableEditorSupport.java:2360)
at org.netbeans.editor.BaseDocument.remove(BaseDocument.java:935)
at **org.netbeans.modules.lsp.client.Utils.lambda$applyEditsNoLock$1(Utils.java:182)**
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.netbeans.modules.lsp.client.Utils.applyEditsNoLock(Utils.java:176)
at org.netbeans.modules.lsp.client.bindings.Formatter.lambda$applyTextEdits$0(Formatter.java:129)
at org.netbeans.editor.GuardedDocument.runAtomic(GuardedDocument.java:296)
at org.openide.text.NbDocument.runAtomic(NbDocument.java:411)
at org.netbeans.modules.lsp.client.bindings.Formatter.applyTextEdits(Formatter.java:128)
at org.netbeans.modules.lsp.client.bindings.Formatter.rangeFormat(Formatter.java:105)
at org.netbeans.modules.lsp.client.bindings.Formatter.reformat(Formatter.java:79)
at org.netbeans.modules.editor.indent.TaskHandler$MimeItem.runTask(TaskHandler.java:550)
at org.netbeans.modules.editor.indent.TaskHandler.runTasks(TaskHandler.java:309)
at org.netbeans.modules.editor.indent.IndentImpl.reformat(IndentImpl.java:349)
at org.netbeans.modules.editor.indent.api.Reformat.reformat(Reformat.java:129)
at org.netbeans.editor.ActionFactory$FormatAction$1$1.run(ActionFactory.java:1854)
at org.netbeans.editor.GuardedDocument.runAtomicAsUser(GuardedDocument.java:333)
at org.netbeans.editor.ActionFactory$FormatAction$1.run(ActionFactory.java:1833)
at org.netbeans.modules.progress.ui.RunOffEDTImpl$1.run(RunOffEDTImpl.java:146)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1418)
at org.netbeans.modules.openide.util.GlobalLookup.execute(GlobalLookup.java:45)
at org.openide.util.lookup.Lookups.executeWith(Lookups.java:278)
at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2033)
Caused: org.openide.util.RequestProcessor$SlowItem
at org.openide.util.RequestProcessor.post(RequestProcessor.java:395)
at org.netbeans.modules.progress.ui.RunOffEDTImpl.runOffEventDispatchThreadImpl(RunOffEDTImpl.java:140)
at org.netbeans.modules.progress.ui.RunOffEDTImpl.runOffEventDispatchThread(RunOffEDTImpl.java:83)
at org.netbeans.api.progress.BaseProgressUtils.runOffEventDispatchThread(BaseProgressUtils.java:90)
at org.netbeans.api.progress.ProgressUtils.runOffEventDispatchThread(ProgressUtils.java:68)
at org.netbeans.editor.ActionFactory$FormatAction.actionPerformed(ActionFactory.java:1821)
at org.netbeans.editor.BaseAction.actionPerformed(BaseAction.java:322)
at org.netbeans.spi.editor.AbstractEditorAction.actionPerformed(AbstractEditorAction.java:445)
at java.desktop/javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1810)
at java.desktop/javax.swing.JComponent.processKeyBinding(JComponent.java:2900)
at java.desktop/javax.swing.JComponent.processKeyBindings(JComponent.java:2948)
at java.desktop/javax.swing.JComponent.processKeyEvent(JComponent.java:2862)
at java.desktop/java.awt.Component.processEvent(Component.java:6412)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
at java.desktop/java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1950)
at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:870)
at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1139)
at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:1009)
at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:835)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4892)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:136)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
[catch] at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

```

### How to reproduce

1- Register Python LSP [pyls](https://github.com/python-lsp/python-lsp-server)
2- Open a simple Python file
3- Invoke netbeans Format feature Alt+Shift+F
4- Formatting failed with stacktrace above

### Did this work correctly in an earlier version?

Apache NetBeans 12.3 or earlier

### Operating System

Windows 10

### JDK

openjdk-11.0.13_8

### Apache NetBeans packaging

Apache NetBeans provided installer

### Anything else

This works fine with another LSP [robot lsp](https://github.com/robocorp/robotframework-lsp/tree/master/robotframework-ls)
But it is not working with the Python LSP one.
After debugging the condition [here](https://github.com/apache/netbeans/blob/862379894fc239268e55f00bb4ce337d4c4437b8/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java#L180) seems very weird to me.

I fixed the issue with:
`if ((startLimit == null || start >= startLimit)
&& (endLimit == null || end >= 0 || endLimit >= 0))
doc.remove(start, end - start < 0 ? endLimit : end - start);` instead

Both text selection format and full document format works well.

### Are you willing to submit a pull request?

Yes

### Code of Conduct

Yes

Contributor guide

Open the contributing guide

Research direction

Start in ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java at applyEditsNoLock(), around line 180, where the stack trace shows the failing removal. Reproduce with the Python LSP pyls, a simple Python file, and Alt+Shift+F, then verify the condition against the reported failure. Done means both selection and full-document formatting complete without the len=-1 exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, python
Domain
devtools
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.