diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionCompletionProposal.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionCompletionProposal.java index 7e5d7ba3d..e99d98790 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionCompletionProposal.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionCompletionProposal.java @@ -11,6 +11,7 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.codeactions; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ContextInformation; import org.eclipse.jface.text.contentassist.ICompletionProposal; @@ -29,8 +30,8 @@ public class CodeActionCompletionProposal implements ICompletionProposal { - private CodeAction fcodeAction; - private Command fcommand; + private @Nullable CodeAction fcodeAction; + private @Nullable Command fcommand; private String fdisplayString; private final LanguageServerWrapper serverWrapper; @@ -39,13 +40,13 @@ public CodeActionCompletionProposal(Either command, Languag if (command.isLeft()) { fcommand = command.getLeft(); fdisplayString = fcommand.getTitle(); - } else if (command.isRight()) { + } else { fcodeAction = command.getRight(); fdisplayString = fcodeAction.getTitle(); } } - static boolean isCodeActionResolveSupported(ServerCapabilities capabilities) { + static boolean isCodeActionResolveSupported(@Nullable ServerCapabilities capabilities) { if (capabilities != null) { Either caProvider = capabilities.getCodeActionProvider(); if (caProvider.isLeft()) { @@ -62,6 +63,7 @@ static boolean isCodeActionResolveSupported(ServerCapabilities capabilities) { @Override public void apply(IDocument document) { + final var fcodeAction = this.fcodeAction; if (fcodeAction != null) { if (isCodeActionResolveSupported(serverWrapper.getServerCapabilities()) && fcodeAction.getEdit() == null) { // Unresolved code action "edit" property. Resolve it. @@ -76,7 +78,7 @@ public void apply(IDocument document) { } } - private void apply(CodeAction codeaction) { + private void apply(@Nullable CodeAction codeaction) { if (codeaction != null) { if (codeaction.getEdit() != null) { LSPEclipseUtils.applyWorkspaceEdit(codeaction.getEdit(), codeaction.getTitle()); @@ -88,13 +90,13 @@ private void apply(CodeAction codeaction) { } @Override - public Point getSelection(IDocument document) { + public @Nullable Point getSelection(IDocument document) { return null; } @Override - public String getAdditionalProposalInfo() { - return ""; //$NON-NLS-1$ + public @Nullable String getAdditionalProposalInfo() { + return null; } @Override @@ -103,12 +105,12 @@ public String getDisplayString() { } @Override - public Image getImage() { + public @Nullable Image getImage() { return null; } @Override - public IContextInformation getContextInformation() { + public @Nullable IContextInformation getContextInformation() { return new ContextInformation("some context display string", "some information display string"); //$NON-NLS-1$//$NON-NLS-2$ } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionMarkerResolution.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionMarkerResolution.java index 0e35472b5..c7f1f3c64 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionMarkerResolution.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CodeActionMarkerResolution.java @@ -20,6 +20,7 @@ import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServerPlugin; import org.eclipse.lsp4e.LanguageServerWrapper; @@ -53,7 +54,7 @@ public String getDescription() { } @Override - public Image getImage() { + public @Nullable Image getImage() { return null; } @@ -127,9 +128,6 @@ private ShowMessageRequestParams reportServerError(LanguageServerDefinition serv @Override public IMarker[] findOtherMarkers(IMarker[] markers) { - if (markers == null) { - return new IMarker[0]; - } return Arrays.stream(markers).filter(marker -> { try { return codeAction.getDiagnostics() diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CommandMarkerResolution.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CommandMarkerResolution.java index 0bdddbd73..4810ee86e 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CommandMarkerResolution.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/CommandMarkerResolution.java @@ -14,7 +14,7 @@ import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.lsp4e.LanguageServerWrapper; import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4e.LanguageServersRegistry.LanguageServerDefinition; @@ -30,9 +30,9 @@ public class CommandMarkerResolution extends WorkbenchMarkerResolution implements IMarkerResolution { - private final @NonNull Command command; + private final Command command; - public CommandMarkerResolution(@NonNull Command command) { + public CommandMarkerResolution(Command command) { this.command = command; } @@ -57,14 +57,12 @@ public void run(IMarker marker) { } LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrapper(resource.getProject(), definition); - if (wrapper != null) { - ExecuteCommandOptions provider = wrapper.getServerCapabilities().getExecuteCommandProvider(); - if (provider != null && provider.getCommands().contains(command.getCommand())) { - wrapper.execute(ls -> ls.getWorkspaceService() - .executeCommand(new ExecuteCommandParams(command.getCommand(), command.getArguments()))); - } else { - CommandExecutor.executeCommandClientSide(command, resource); - } + ExecuteCommandOptions provider = wrapper.getServerCapabilities().getExecuteCommandProvider(); + if (provider != null && provider.getCommands().contains(command.getCommand())) { + wrapper.execute(ls -> ls.getWorkspaceService() + .executeCommand(new ExecuteCommandParams(command.getCommand(), command.getArguments()))); + } else { + CommandExecutor.executeCommandClientSide(command, resource); } } @@ -74,7 +72,7 @@ public String getDescription() { } @Override - public Image getImage() { + public @Nullable Image getImage() { return null; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionMarkerResolution.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionMarkerResolution.java index 84a3b384e..0e4d480f3 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionMarkerResolution.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionMarkerResolution.java @@ -29,6 +29,7 @@ import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.AbstractInformationControlManager; import org.eclipse.jface.text.ITextHover; @@ -200,7 +201,7 @@ private void reinvokeQuickfixProposalsIfNecessary(ITextViewer textViewer) { } } - static boolean providesCodeActions(final ServerCapabilities capabilities) { + static boolean providesCodeActions(final @Nullable ServerCapabilities capabilities) { return capabilities != null && LSPEclipseUtils.hasCapability(capabilities.getCodeActionProvider()); } @@ -219,7 +220,7 @@ public boolean hasResolutions(IMarker marker) { return false; } - static boolean canPerform(Either command) { + static boolean canPerform(@Nullable Either command) { if (command == null) { return false; } @@ -241,7 +242,7 @@ static boolean canPerform(Either command) { TextDocumentEdit textedit = change.getLeft(); VersionedTextDocumentIdentifier id = textedit.getTextDocument(); URI uri = URI.create(id.getUri()); - if (uri != null && LSPEclipseUtils.isReadOnly(uri)) { + if (LSPEclipseUtils.isReadOnly(uri)) { return false; } } @@ -251,7 +252,7 @@ static boolean canPerform(Either command) { if (changes != null) { for (java.util.Map.Entry> textEdit : changes.entrySet()) { URI uri = URI.create(textEdit.getKey()); - if (uri != null && LSPEclipseUtils.isReadOnly(uri)) { + if (LSPEclipseUtils.isReadOnly(uri)) { return false; } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionQuickAssistProcessor.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionQuickAssistProcessor.java index ef44531e2..46ef8843c 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionQuickAssistProcessor.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionQuickAssistProcessor.java @@ -19,10 +19,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; @@ -44,8 +44,8 @@ public class LSPCodeActionQuickAssistProcessor implements IQuickAssistProcessor { // Data necessary for caching proposals - private Object lock = new Object(); - private IQuickAssistInvocationContext cachedContext; + private final Object lock = new Object(); + private @Nullable IQuickAssistInvocationContext cachedContext; private List proposals = Collections.synchronizedList(new ArrayList<>()); private static final ICompletionProposal COMPUTING = new ICompletionProposal() { @@ -56,12 +56,12 @@ public void apply(IDocument document) { } @Override - public Point getSelection(IDocument document) { + public @Nullable Point getSelection(IDocument document) { return null; } @Override - public String getAdditionalProposalInfo() { + public @Nullable String getAdditionalProposalInfo() { return null; } @@ -71,19 +71,16 @@ public String getDisplayString() { } @Override - public Image getImage() { + public @Nullable Image getImage() { return JFaceResources.getImage(ProgressInfoItem.class.getPackageName() + ".PROGRESS_DEFAULT"); //$NON-NLS-1$ } @Override - public IContextInformation getContextInformation() { + public @Nullable IContextInformation getContextInformation() { return null; } - }; - CompletionProposal[] NO_PROPOSALS = {}; - @Override public String getErrorMessage() { return "CodeActions not implemented on this Language Server"; //$NON-NLS-1$ @@ -105,14 +102,14 @@ public boolean canAssist(IQuickAssistInvocationContext invocationContext) { } @Override - public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) { + public ICompletionProposal @Nullable [] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) { IDocument document = invocationContext.getSourceViewer().getDocument(); if (document == null) { - return NO_PROPOSALS; + return null; } LanguageServerDocumentExecutor executor = LanguageServers.forDocument(document).withFilter(LSPCodeActionMarkerResolution::providesCodeActions); if (!executor.anyMatching()) { - return NO_PROPOSALS; + return null; } // If context has changed, i.e. new quick assist invocation rather than old @@ -120,14 +117,15 @@ public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationC // the UI boolean needNewQuery = true; synchronized (lock) { - needNewQuery = cachedContext == null || invocationContext == null || + final var cachedContext = this.cachedContext; + needNewQuery = cachedContext == null || cachedContext.getClass() != invocationContext.getClass() || cachedContext.getSourceViewer() != invocationContext.getSourceViewer() || cachedContext.getOffset() != invocationContext.getOffset() || cachedContext.getLength() != invocationContext.getLength(); // should also check whether (same) document content changed if (needNewQuery) { - cachedContext = invocationContext; + this.cachedContext = invocationContext; } } @@ -138,7 +136,7 @@ public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationC proposals.clear(); // Start all the servers computing actions - each server will append any code actions to the ongoing list of proposals // as a side effect of this request - List> futures = executor.computeAll((w, ls) -> ls.getTextDocumentService() + List> futures = executor.computeAll((w, ls) -> ls.getTextDocumentService() .codeAction(params) .thenAccept(actions -> LanguageServers.streamSafely(actions) .filter(LSPCodeActionMarkerResolution::canPerform) @@ -156,7 +154,7 @@ public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationC // Server calls didn't complete in time; those that did will have added their results to this.proposals and can be returned // as an intermediate result; as we're returning control to the UI, we need any stragglers to trigger a refresh when they arrive later on proposals.add(COMPUTING); - for (CompletableFuture future : futures) { + for (CompletableFuture<@Nullable Void> future : futures) { // Refresh will effectively re-enter this method with the same invocationContext and already computed proposals simply to show the proposals in the UI future.whenComplete((r, t) -> { if (futures.stream().allMatch(CompletableFuture::isDone)) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionsMenu.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionsMenu.java index 6f3446ed9..4a46132ec 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionsMenu.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/LSPCodeActionsMenu.java @@ -12,6 +12,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.codeactions; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.lateNonNull; + import java.net.URI; import java.util.Collections; import java.util.List; @@ -20,7 +22,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -52,8 +54,8 @@ public class LSPCodeActionsMenu extends ContributionItem implements IWorkbenchContribution { - private IDocument document; - private Range range; + private IDocument document = lateNonNull(); + private Range range = lateNonNull(); @Override public void initialize(IServiceLocator serviceLocator) { @@ -81,7 +83,7 @@ public void fill(final Menu menu, int index) { item.setEnabled(false); item.setText(Messages.computing); - final @NonNull IDocument document = this.document; + final IDocument document = this.document; final URI fileUri = LSPEclipseUtils.toUri(document); final var context = new CodeActionContext(Collections.emptyList()); @@ -90,10 +92,10 @@ public void fill(final Menu menu, int index) { params.setRange(this.range); params.setContext(context); - final @NonNull List<@NonNull CompletableFuture>>> actions - = LanguageServers.forDocument(document).withFilter(LSPCodeActionMarkerResolution::providesCodeActions) - .computeAll((w, ls) -> ls.getTextDocumentService().codeAction(params) - .whenComplete((codeActions, t) -> scheduleMenuUpdate(menu, item, index, document, w, t, codeActions))); + final List>>> actions = LanguageServers.forDocument(document) + .withFilter(LSPCodeActionMarkerResolution::providesCodeActions) + .computeAll((w, ls) -> ls.getTextDocumentService().codeAction(params).whenComplete( + (codeActions, t) -> scheduleMenuUpdate(menu, item, index, document, w, t, codeActions))); if (actions.isEmpty()) { item.setText(Messages.notImplemented); @@ -103,10 +105,12 @@ public void fill(final Menu menu, int index) { super.fill(menu, index); } - private void scheduleMenuUpdate(final Menu menu, final MenuItem placeHolder, final int index, final IDocument document, final LanguageServerWrapper wrapper, final Throwable ex, final List> codeActions) { + private void scheduleMenuUpdate(final Menu menu, final MenuItem placeHolder, final int index, + final IDocument document, final LanguageServerWrapper wrapper, final @Nullable Throwable ex, + final @Nullable List<@Nullable Either> codeActions) { final var job = new UIJob(menu.getDisplay(), Messages.updateCodeActions_menu) { @Override - public IStatus runInUIThread(IProgressMonitor monitor) { + public IStatus runInUIThread(@Nullable IProgressMonitor monitor) { if (ex != null) { final var item = new MenuItem(menu, SWT.NONE, index); item.setText(String.valueOf(ex.getMessage())); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/package-info.java new file mode 100644 index 000000000..1ada6a32f --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codeactions/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.codeactions; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java index ad21a57c7..bf26be5b2 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java @@ -14,7 +14,7 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; @@ -30,24 +30,24 @@ public class CodeLensProvider extends AbstractCodeMiningProvider { - private CompletableFuture> provideCodeMinings(@NonNull IDocument document) { + private @Nullable CompletableFuture> provideCodeMinings(IDocument document) { URI docURI = LSPEclipseUtils.toUri(document); if (docURI != null) { final var param = new CodeLensParams(LSPEclipseUtils.toTextDocumentIdentifier(docURI)); LanguageServerDocumentExecutor executor = LanguageServers.forDocument(document) .withFilter(sc -> sc.getCodeLensProvider() != null); - return executor.collectAll((w, ls) -> ls.getTextDocumentService().codeLens(param) - .thenApply(codeLenses -> LanguageServers.streamSafely(codeLenses) - .map(codeLens -> toCodeMining(document, w, codeLens)) - .filter(Objects::nonNull))) - .thenApply(result -> result.stream().flatMap(s -> s).toList()); - } - else { + return executor + .collectAll((w, ls) -> ls.getTextDocumentService().codeLens(param) + .thenApply(codeLenses -> LanguageServers.streamSafely(codeLenses) + .map(codeLens -> toCodeMining(document, w, codeLens)).filter(Objects::nonNull))) + .thenApply(result -> result.stream().flatMap(s -> s).toList()); + } else { return null; } } - private LSPCodeMining toCodeMining(IDocument document, LanguageServerWrapper languageServerWrapper, CodeLens codeLens) { + private @Nullable LSPCodeMining toCodeMining(IDocument document, LanguageServerWrapper languageServerWrapper, + @Nullable CodeLens codeLens) { if (codeLens == null) { return null; } @@ -60,7 +60,7 @@ private LSPCodeMining toCodeMining(IDocument document, LanguageServerWrapper lan } @Override - public CompletableFuture> provideCodeMinings(ITextViewer viewer, + public @Nullable CompletableFuture> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) { IDocument document = viewer.getDocument(); return document != null ? provideCodeMinings(document) : null; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java index d916b6683..fa3890fc9 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java @@ -12,7 +12,6 @@ import java.util.function.Consumer; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -30,9 +29,9 @@ public class LSPCodeMining extends LineHeaderCodeMining { private CodeLens codeLens; private final LanguageServerWrapper languageServerWrapper; - private final @NonNull IDocument document; + private final IDocument document; - public LSPCodeMining(CodeLens codeLens, @NonNull IDocument document, LanguageServerWrapper languageServerWrapper, + public LSPCodeMining(CodeLens codeLens, IDocument document, LanguageServerWrapper languageServerWrapper, CodeLensProvider provider) throws BadLocationException { super(codeLens.getRange().getStart().getLine(), document, provider, null); this.codeLens = codeLens; @@ -41,7 +40,7 @@ public LSPCodeMining(CodeLens codeLens, @NonNull IDocument document, LanguageSer setLabel(getCodeLensString(codeLens)); } - protected static @Nullable String getCodeLensString(@NonNull CodeLens codeLens) { + protected static @Nullable String getCodeLensString(CodeLens codeLens) { Command command = codeLens.getCommand(); if (command == null || command.getTitle().isEmpty()) { return null; @@ -66,7 +65,7 @@ protected CompletableFuture doResolve(ITextViewer viewer, IProgressMonitor } @Override - public final Consumer getAction() { + public final @Nullable Consumer getAction() { final Command command = codeLens.getCommand(); if(command != null && command.getCommand() != null && !command.getCommand().isEmpty()) { return this::performAction; @@ -86,5 +85,4 @@ private void performAction(MouseEvent mouseEvent) { } } - } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/package-info.java new file mode 100644 index 000000000..7832f693f --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.codelens; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java index 4972db60d..408b83a4e 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java @@ -13,7 +13,6 @@ import java.util.function.Consumer; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; @@ -102,7 +101,7 @@ public void accept(MouseEvent event) { } } - public ColorInformationMining(ColorInformation colorInformation, @NonNull IDocument document, + public ColorInformationMining(ColorInformation colorInformation, IDocument document, TextDocumentIdentifier textDocumentIdentifier, LanguageServerWrapper languageServerWrapper, DocumentColorProvider colorProvider) throws BadLocationException { super(toPosition(colorInformation.getRange(), document), colorProvider, diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java index dbfe56029..5282491d0 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java @@ -20,7 +20,7 @@ import java.util.function.Function; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; @@ -51,7 +51,7 @@ public DocumentColorProvider() { colorTable = new HashMap<>(); } - private CompletableFuture> provideCodeMinings(@NonNull IDocument document) { + private @Nullable CompletableFuture> provideCodeMinings(IDocument document) { URI docURI = LSPEclipseUtils.toUri(document); if (docURI != null) { @@ -71,7 +71,7 @@ private CompletableFuture> provideCodeMinings(@NonNu } } - private ColorInformationMining toMining(ColorInformation color, @NonNull IDocument document, TextDocumentIdentifier textDocumentIdentifier, LanguageServerWrapper wrapper) { + private @Nullable ColorInformationMining toMining(ColorInformation color, IDocument document, TextDocumentIdentifier textDocumentIdentifier, LanguageServerWrapper wrapper) { try { return new ColorInformationMining(color, document, textDocumentIdentifier, wrapper, @@ -83,7 +83,7 @@ private ColorInformationMining toMining(ColorInformation color, @NonNull IDocume } @Override - public CompletableFuture> provideCodeMinings(ITextViewer viewer, + public @Nullable CompletableFuture> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) { IDocument document = viewer.getDocument(); return document != null ? provideCodeMinings(document) : null; @@ -102,7 +102,7 @@ public Color getColor(RGBA rgba, Display display) { return colorTable.computeIfAbsent(rgba, key -> new Color(display, rgba)); } - private static boolean isColorProvider(final ServerCapabilities capabilities) { + private static boolean isColorProvider(final @Nullable ServerCapabilities capabilities) { return capabilities != null && LSPEclipseUtils.hasCapability(capabilities.getColorProvider()); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/package-info.java new file mode 100644 index 000000000..a0d3536ae --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.color; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionProposalTools.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionProposalTools.java index cb55528f9..97aee48dd 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionProposalTools.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionProposalTools.java @@ -150,7 +150,7 @@ public static int getScoreOfFilterMatch(String documentFilter, String completion } private static int getScoreOfFilterMatchHelper(int prefixLength, String documentFilter, String completionFilter) { - if (documentFilter == null || documentFilter.isEmpty()) { + if (documentFilter.isEmpty()) { return 0; } char searchChar = documentFilter.charAt(0); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionSnippetParser.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionSnippetParser.java index 54f36dde8..a4be7779e 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionSnippetParser.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/CompletionSnippetParser.java @@ -24,7 +24,6 @@ import org.eclipse.jface.text.link.LinkedPosition; import org.eclipse.jface.text.link.ProposalPosition; - /** * A parser for the completion insert text in * snippet syntax diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSCompletionProposal.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSCompletionProposal.java index 81e122dad..801261440 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSCompletionProposal.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSCompletionProposal.java @@ -16,10 +16,13 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.completion; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -29,7 +32,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.internal.text.html.BrowserInformationControl; import org.eclipse.jface.text.AbstractReusableInformationControlCreator; import org.eclipse.jface.text.BadLocationException; @@ -118,25 +121,25 @@ public class LSCompletionProposal private final int initialOffset; protected int bestOffset = -1; protected int currentOffset = -1; - protected ITextViewer viewer; + protected @Nullable ITextViewer viewer; private final IDocument document; private final boolean isIncomplete; - private IRegion selection; - private LinkedPosition firstPosition; + private @Nullable IRegion selection; + private @Nullable LinkedPosition firstPosition; // private LSPDocumentInfo info; - private Integer rankCategory; - private Integer rankScore; - private String documentFilter; + private @Nullable Integer rankCategory; + private @Nullable Integer rankScore; + private @Nullable String documentFilter; private String documentFilterAddition = ""; //$NON-NLS-1$ private final LanguageServerWrapper languageServerWrapper; - public LSCompletionProposal(@NonNull IDocument document, int offset, @NonNull CompletionItem item, + public LSCompletionProposal(IDocument document, int offset, CompletionItem item, LanguageServerWrapper languageServerWrapper) { this(document, offset, item, null, languageServerWrapper, false); } - public LSCompletionProposal(@NonNull IDocument document, int offset, @NonNull CompletionItem item, - CompletionItemDefaults defaults, LanguageServerWrapper languageServerWrapper, boolean isIncomplete) { + public LSCompletionProposal(IDocument document, int offset, CompletionItem item, + @Nullable CompletionItemDefaults defaults, LanguageServerWrapper languageServerWrapper, boolean isIncomplete) { this.item = item; this.document = document; this.languageServerWrapper = languageServerWrapper; @@ -193,8 +196,8 @@ public String getDocumentFilter() throws BadLocationException { if (documentFilter != null) { return documentFilter + documentFilterAddition; } - documentFilter = CompletionProposalTools.getFilterFromDocument(document, currentOffset, - getFilterString(), bestOffset); + final var documentFilter = this.documentFilter = CompletionProposalTools.getFilterFromDocument(document, + currentOffset, getFilterString(), bestOffset); documentFilterAddition = ""; //$NON-NLS-1$ return documentFilter; } @@ -208,6 +211,7 @@ public String getDocumentFilter() throws BadLocationException { public int getRankScore() { if (rankScore != null) return rankScore; + int rankScore; try { rankScore = CompletionProposalTools.getScoreOfFilterMatch(getDocumentFilter(), getFilterString()); @@ -215,6 +219,7 @@ public int getRankScore() { LanguageServerPlugin.logError(e); rankScore = -1; } + this.rankScore = rankScore; return rankScore; } @@ -229,6 +234,7 @@ public int getRankCategory() { if (rankCategory != null) { return rankCategory; } + int rankCategory; try { rankCategory = CompletionProposalTools.getCategoryOfFilterMatch(getDocumentFilter(), getFilterString()); @@ -236,6 +242,7 @@ public int getRankCategory() { LanguageServerPlugin.logError(e); rankCategory = 5; } + this.rankCategory = rankCategory; return rankCategory; } @@ -312,7 +319,7 @@ public boolean isAutoInsertable() { } @Override - public IInformationControlCreator getInformationControlCreator() { + public @Nullable IInformationControlCreator getInformationControlCreator() { return new AbstractReusableInformationControlCreator() { @Override protected IInformationControl doCreateInformationControl(Shell parent) { @@ -348,7 +355,7 @@ public String getAdditionalProposalInfo(IProgressMonitor monitor) { return res.toString(); } - private boolean resolvesCompletionItem(final ServerCapabilities capabilities) { + private boolean resolvesCompletionItem(final @Nullable ServerCapabilities capabilities) { if (capabilities != null) { CompletionOptions completionProvider = capabilities.getCompletionProvider(); if (completionProvider != null) { @@ -373,7 +380,7 @@ private void resolveItem() { } } - private void updateCompletionItem(CompletionItem resolvedItem) { + private void updateCompletionItem(@Nullable CompletionItem resolvedItem) { if (resolvedItem == null) { return; } @@ -404,7 +411,7 @@ private void updateCompletionItem(CompletionItem resolvedItem) { } @Override - public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) { + public @Nullable CharSequence getPrefixCompletionText(IDocument document, int completionOffset) { return item.getInsertText().substring(completionOffset - bestOffset); } @@ -532,6 +539,7 @@ protected void apply(IDocument document, char trigger, int stateMask, int offset } boolean onlyPlaceCaret = regions.size() == 1 && regions.values().iterator().next().size() == 1 && regions.values().iterator().next().stream().noneMatch(ProposalPosition.class::isInstance); + final var viewer = this.viewer; if (viewer != null && !regions.isEmpty() && !onlyPlaceCaret) { final var model = new LinkedModeModel(); for (List positions: regions.values()) { @@ -583,7 +591,7 @@ private String adjustIndentation(IDocument document, String insertText, int inse return insertText.replace("\n", whitespacesBeforeInsertion); //$NON-NLS-1$ } - private int computeNewOffset(List additionalTextEdits, int insertionOffset, IDocument doc) { + private int computeNewOffset(@Nullable List additionalTextEdits, int insertionOffset, IDocument doc) { if (additionalTextEdits != null && !additionalTextEdits.isEmpty()) { int adjustment = 0; for (TextEdit edit : additionalTextEdits) { @@ -613,7 +621,10 @@ private String getVariableValue(String variableName) { String fileName = pathBase.lastSegment(); yield fileName != null ? fileName : ""; //$NON-NLS-1$ } - case TM_FILENAME -> LSPEclipseUtils.toPath(document).lastSegment(); + case TM_FILENAME -> { + String fileName = LSPEclipseUtils.toPath(document).lastSegment(); + yield fileName != null ? fileName : ""; //$NON-NLS-1$ + } case TM_FILEPATH -> getAbsoluteLocation(LSPEclipseUtils.toPath(document)); case TM_DIRECTORY -> getAbsoluteLocation(LSPEclipseUtils.toPath(document).removeLastSegments(1)); case TM_LINE_INDEX -> { @@ -645,6 +656,7 @@ private String getVariableValue(String variableName) { } case TM_SELECTED_TEXT -> { try { + final var viewer = castNonNull(this.viewer); String selectedText = document.get(viewer.getSelectedRange().x, viewer.getSelectedRange().y); yield selectedText; } catch (BadLocationException e) { @@ -654,6 +666,7 @@ private String getVariableValue(String variableName) { } case TM_CURRENT_WORD -> { try { + final var viewer = castNonNull(this.viewer); String selectedText = document.get(viewer.getSelectedRange().x, viewer.getSelectedRange().y); int beforeSelection = viewer.getSelectedRange().x - 1; while (beforeSelection >= 0 && Character.isUnicodeIdentifierPart(document.getChar(beforeSelection))) { @@ -718,10 +731,12 @@ protected String getInsertText() { } @Override - public Point getSelection(IDocument document) { + public @Nullable Point getSelection(IDocument document) { + final var firstPosition = this.firstPosition; if (firstPosition != null) { return new Point(firstPosition.getOffset(), firstPosition.getLength()); } + final var selection = this.selection; if (selection == null) { return null; } @@ -729,28 +744,28 @@ public Point getSelection(IDocument document) { } @Override - public String getAdditionalProposalInfo() { + public @Nullable String getAdditionalProposalInfo() { return getAdditionalProposalInfo(new NullProgressMonitor()); } @Override - public Image getImage() { + public @Nullable Image getImage() { return LSPImages.imageFromCompletionItem(item); } @Override - public IContextInformation getContextInformation() { + public @Nullable IContextInformation getContextInformation() { return this; } @Override public String getContextDisplayString() { - return getAdditionalProposalInfo(); + return Objects.toString(getAdditionalProposalInfo()); } @Override public String getInformationDisplayString() { - return getAdditionalProposalInfo(); + return Objects.toString(getAdditionalProposalInfo()); } public String getSortText() { @@ -782,7 +797,7 @@ public void unselected(ITextViewer viewer) { } @Override - public boolean validate(IDocument document, int offset, DocumentEvent event) { + public boolean validate(IDocument document, int offset, @Nullable DocumentEvent event) { if (item.getLabel() == null || item.getLabel().isEmpty()) { return false; } @@ -805,7 +820,10 @@ public boolean validate(IDocument document, int offset, DocumentEvent event) { @Override public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { this.viewer = viewer; - apply(viewer.getDocument(), trigger, stateMask, offset); + final var doc = viewer.getDocument(); + if (doc != null) { + apply(doc, trigger, stateMask, offset); + } } @Override @@ -819,7 +837,7 @@ public void apply(IDocument document) { } @Override - public char[] getTriggerCharacters() { + public char @Nullable [] getTriggerCharacters() { return null; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSContentAssistProcessor.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSContentAssistProcessor.java index 8a1128597..662b10407 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSContentAssistProcessor.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/LSContentAssistProcessor.java @@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; @@ -68,18 +68,18 @@ public class LSContentAssistProcessor implements IContentAssistProcessor { private static final long TRIGGERS_TIMEOUT = 50; private static final long CONTEXT_INFORMATION_TIMEOUT = 1000; - private IDocument currentDocument; - private String errorMessage; + private @Nullable IDocument currentDocument; + private @Nullable String errorMessage; private final boolean errorAsCompletionItem; - private CompletableFuture<@NonNull List<@NonNull Void>> completionLanguageServersFuture; + private @Nullable CompletableFuture> completionLanguageServersFuture; private final Object completionTriggerCharsSemaphore = new Object(); private char[] completionTriggerChars = new char[0]; - private CompletableFuture<@NonNull List<@NonNull Void>> contextInformationLanguageServersFuture; + private @Nullable CompletableFuture> contextInformationLanguageServersFuture; private final Object contextTriggerCharsSemaphore = new Object(); private char[] contextTriggerChars = new char[0]; private final boolean incompleteAsCompletionItem; - // The cancellation support used to cancel previous LSP requests 'textDocument/completion' when completion is retriggered + /** The cancellation support used to cancel previous LSP requests 'textDocument/completion' when completion is retriggered */ private CancellationSupport cancellationSupport; public LSContentAssistProcessor() { @@ -99,7 +99,7 @@ public LSContentAssistProcessor(boolean errorAsCompletionItem, boolean incomplet private final Comparator proposalComparator = new LSCompletionProposalComparator(); @Override - public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { + public ICompletionProposal @Nullable [] computeCompletionProposals(ITextViewer viewer, int offset) { IDocument document = viewer.getDocument(); if (document == null) { return new LSCompletionProposal[0]; @@ -131,28 +131,34 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int // - LSP requests 'textDocument/completions' // - completionLanguageServersFuture CancellationSupport cancellationSupport = new CancellationSupport(); - this.completionLanguageServersFuture = LanguageServers.forDocument(document) + final var completionLanguageServersFuture = this.completionLanguageServersFuture = LanguageServers.forDocument(document) .withFilter(capabilities -> capabilities.getCompletionProvider() != null) // .collectAll((w, ls) -> cancellationSupport.execute(ls.getTextDocumentService().completion(param)) // .thenAccept(completion -> { - boolean isIncomplete = completion != null && completion.isRight() ? completion.getRight().isIncomplete() : false; - proposals.addAll(toProposals(document, offset, completion, w, cancellationSupport, isIncomplete)); + boolean isIncomplete = completion != null && completion.isRight() + ? completion.getRight().isIncomplete() + : false; + proposals.addAll(toProposals(document, offset, completion, w, cancellationSupport, + isIncomplete)); if (isIncomplete) { anyIncomplete.set(true); } }).exceptionally(t -> { if (!CancellationUtil.isRequestCancelledException(t)) { - LanguageServerPlugin.logError("'%s' LS failed to compute completion items.".formatted(w.serverDefinition.label), t); //$NON-NLS-1$ + LanguageServerPlugin.logError("'%s' LS failed to compute completion items." //$NON-NLS-1$ + .formatted(w.serverDefinition.label), t); } return null; })); cancellationSupport.execute(completionLanguageServersFuture); this.cancellationSupport = cancellationSupport; - // Wait for the result of all LSP requests 'textDocument/completions', this future will be canceled with the next completion - this.completionLanguageServersFuture.get(); + // Wait for the result of all LSP requests 'textDocument/completions', this + // future will be canceled with the next completion + completionLanguageServersFuture.get(); } catch (ExecutionException e) { - // Ideally exceptions from each LS are handled above and we shouldn't be getting into this block + // Ideally exceptions from each LS are handled above and we shouldn't be getting + // into this block this.errorMessage = createErrorMessage(offset, e); return createErrorProposal(offset, e); } catch (InterruptedException e) { @@ -175,8 +181,10 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int Arrays.sort(completeProposals, proposalComparator); ICompletionProposal[] incompleteProposal = createIncompleProposal(offset, anyIncomplete.get()); if (incompleteProposal.length > 0) { - ICompletionProposal[] incompleteProposals = Arrays.copyOf(completeProposals, completeProposals.length + incompleteProposal.length, ICompletionProposal[].class); - System.arraycopy(incompleteProposal, 0, incompleteProposals, completeProposals.length, incompleteProposal.length); + ICompletionProposal[] incompleteProposals = Arrays.copyOf(completeProposals, + completeProposals.length + incompleteProposal.length, ICompletionProposal[].class); + System.arraycopy(incompleteProposal, 0, incompleteProposals, completeProposals.length, + incompleteProposal.length); return incompleteProposals; } return completeProposals; @@ -184,9 +192,9 @@ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int private ICompletionProposal[] createErrorProposal(int offset, Exception ex) { if (errorAsCompletionItem) { - return new ICompletionProposal[] {new CompletionProposal("", offset, 0, 0, null, Messages.completionError, null, ex.getMessage())}; //$NON-NLS-1$ - } - else { + return new ICompletionProposal[] { + new CompletionProposal("", offset, 0, 0, null, Messages.completionError, null, ex.getMessage()) }; //$NON-NLS-1$ + } else { return new ICompletionProposal[0]; } } @@ -197,12 +205,13 @@ private String createErrorMessage(int offset, Exception ex) { private ICompletionProposal[] createIncompleProposal(int offset, boolean incomplete) { if (incompleteAsCompletionItem && incomplete) { - return new ICompletionProposal[] {new CompletionProposal("", offset, 0, 0, null, Messages.completionIncomplete, null, Messages.continueIncomplete)}; //$NON-NLS-1$ + return new ICompletionProposal[] { new CompletionProposal("", offset, 0, 0, null, //$NON-NLS-1$ + Messages.completionIncomplete, null, Messages.continueIncomplete) }; } return new ICompletionProposal[0]; } - private void initiateLanguageServers(@NonNull IDocument document) { + private void initiateLanguageServers(IDocument document) { if (currentDocument != document) { this.currentDocument = document; if (this.completionLanguageServersFuture != null) { @@ -245,38 +254,38 @@ private void initiateLanguageServers(@NonNull IDocument document) { private void initiateLanguageServers() { ITextEditor textEditor = UI.getActiveTextEditor(); - if(textEditor != null) { + if (textEditor != null) { IDocument document = LSPEclipseUtils.getDocument(textEditor); if (document != null) { initiateLanguageServers(document); } } } - private static List toProposals(IDocument document, - int offset, Either, CompletionList> completionList, LanguageServerWrapper languageServerWrapper, CancelChecker cancelChecker, boolean isIncomplete) { + + private static List toProposals(IDocument document, int offset, + @Nullable Either, CompletionList> completionList, LanguageServerWrapper languageServerWrapper, + CancelChecker cancelChecker, boolean isIncomplete) { if (completionList == null) { return Collections.emptyList(); } - //Stop the compute of ICompletionProposal if the completion has been cancelled + // Stop the compute of ICompletionProposal if the completion has been cancelled cancelChecker.checkCanceled(); CompletionItemDefaults defaults = completionList.map(o -> null, CompletionList::getItemDefaults); - List items = completionList.isLeft() ? completionList.getLeft() : completionList.getRight().getItems(); + List items = completionList.isLeft() ? completionList.getLeft() + : completionList.getRight().getItems(); return items.stream() // - .filter(Objects::nonNull) - .map(item -> new LSCompletionProposal(document, offset, item, defaults, + .filter(Objects::nonNull).map(item -> new LSCompletionProposal(document, offset, item, defaults, languageServerWrapper, isIncomplete)) .filter(proposal -> { - //Stop the compute of ICompletionProposal if the completion has been cancelled + // Stop the compute of ICompletionProposal if the completion has been cancelled cancelChecker.checkCanceled(); return true; - }) - .filter(proposal -> proposal.validate(document, offset, null)) - .map(ICompletionProposal.class::cast) + }).filter(proposal -> proposal.validate(document, offset, null)).map(ICompletionProposal.class::cast) .toList(); } @Override - public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { + public IContextInformation @Nullable [] computeContextInformation(ITextViewer viewer, int offset) { IDocument document = viewer.getDocument(); if (document == null) { return new IContextInformation[] { /* TODO? show error in context information */ }; @@ -292,17 +301,17 @@ public IContextInformation[] computeContextInformation(ITextViewer viewer, int o List contextInformations = Collections.synchronizedList(new ArrayList<>()); try { this.contextInformationLanguageServersFuture = LanguageServers.forDocument(document) - .withFilter(capabilities -> capabilities.getSignatureHelpProvider() != null).collectAll( - ls -> ls.getTextDocumentService().signatureHelp(param).thenAccept(signatureHelp -> { - if (signatureHelp != null) { - signatureHelp.getSignatures().stream() - .map(LSContentAssistProcessor::toContextInformation) - .forEach(contextInformations::add); - } - })); + .withFilter(capabilities -> capabilities.getSignatureHelpProvider() != null) + .collectAll(ls -> ls.getTextDocumentService().signatureHelp(param).thenAccept(signatureHelp -> { + if (signatureHelp != null) { + signatureHelp.getSignatures().stream().map(LSContentAssistProcessor::toContextInformation) + .forEach(contextInformations::add); + } + })); this.contextInformationLanguageServersFuture.get(CONTEXT_INFORMATION_TIMEOUT, TimeUnit.MILLISECONDS); } catch (ResponseErrorException | ExecutionException e) { - if (!CancellationUtil.isRequestCancelledException(e)) { // do not report error if the server has cancelled the request + if (!CancellationUtil.isRequestCancelledException(e)) { // do not report error if the server has cancelled + // the request LanguageServerPlugin.logError(e); } return new IContextInformation[] { /* TODO? show error in context information */ }; @@ -311,7 +320,8 @@ public IContextInformation[] computeContextInformation(ITextViewer viewer, int o Thread.currentThread().interrupt(); return new IContextInformation[] { /* TODO? show error in context information */ }; } catch (TimeoutException e) { - LanguageServerPlugin.logWarning("Could not compute context information due to timeout after " + CONTEXT_INFORMATION_TIMEOUT + " milliseconds", e); //$NON-NLS-1$//$NON-NLS-2$ + LanguageServerPlugin.logWarning("Could not compute context information due to timeout after " //$NON-NLS-1$ + + CONTEXT_INFORMATION_TIMEOUT + " milliseconds", e); //$NON-NLS-1$ return new IContextInformation[] { /* TODO? show error in context information */ }; } return contextInformations.toArray(IContextInformation[]::new); @@ -320,14 +330,14 @@ public IContextInformation[] computeContextInformation(ITextViewer viewer, int o private static IContextInformation toContextInformation(SignatureInformation information) { final var signature = new StringBuilder(information.getLabel()); String docString = LSPEclipseUtils.getDocString(information.getDocumentation()); - if (docString!=null && !docString.isEmpty()) { + if (docString != null && !docString.isEmpty()) { signature.append('\n').append(docString); } return new ContextInformation(information.getLabel(), signature.toString()); } - private void getFuture(CompletableFuture<@NonNull List<@NonNull Void>> future) { - if(future == null) { + private void getFuture(@Nullable CompletableFuture> future) { + if (future == null) { return; } @@ -337,15 +347,17 @@ private void getFuture(CompletableFuture<@NonNull List<@NonNull Void>> future) { LanguageServerPlugin.logError(e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { - LanguageServerPlugin.logWarning("Could not get trigger characters due to timeout after " + TRIGGERS_TIMEOUT + " milliseconds", e); //$NON-NLS-1$//$NON-NLS-2$ + LanguageServerPlugin.logWarning( + "Could not get trigger characters due to timeout after " + TRIGGERS_TIMEOUT + " milliseconds", e); //$NON-NLS-1$//$NON-NLS-2$ } catch (OperationCanceledException | ResponseErrorException | ExecutionException | CancellationException e) { - if (!CancellationUtil.isRequestCancelledException(e)) { // do not report error if the server has cancelled the request + if (!CancellationUtil.isRequestCancelledException(e)) { // do not report error if the server has cancelled + // the request LanguageServerPlugin.logError(e); } } } - private static char[] mergeTriggers(char[] initialArray, Collection additionalTriggers) { + private static char[] mergeTriggers(char @Nullable [] initialArray, @Nullable Collection additionalTriggers) { if (initialArray == null) { initialArray = new char[0]; } @@ -356,8 +368,8 @@ private static char[] mergeTriggers(char[] initialArray, Collection addi for (char c : initialArray) { triggers.add(c); } - additionalTriggers.stream().filter(s -> !Strings.isNullOrEmpty(s)) - .map(triggerChar -> triggerChar.charAt(0)).forEach(triggers::add); + additionalTriggers.stream().filter(s -> !Strings.isNullOrEmpty(s)).map(triggerChar -> triggerChar.charAt(0)) + .forEach(triggers::add); char[] res = new char[triggers.size()]; int i = 0; for (Character c : triggers) { @@ -368,26 +380,26 @@ private static char[] mergeTriggers(char[] initialArray, Collection addi } @Override - public char[] getCompletionProposalAutoActivationCharacters() { + public char @Nullable [] getCompletionProposalAutoActivationCharacters() { initiateLanguageServers(); getFuture(completionLanguageServersFuture); return completionTriggerChars; } @Override - public char[] getContextInformationAutoActivationCharacters() { + public char @Nullable [] getContextInformationAutoActivationCharacters() { initiateLanguageServers(); getFuture(contextInformationLanguageServersFuture); return contextTriggerChars; } @Override - public String getErrorMessage() { + public @Nullable String getErrorMessage() { return this.errorMessage; } @Override - public IContextInformationValidator getContextInformationValidator() { + public @Nullable IContextInformationValidator getContextInformationValidator() { return new ContextInformationValidator(this); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/package-info.java new file mode 100644 index 000000000..96e2a34b1 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/completion/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.completion; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/LSBasedHyperlink.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/LSBasedHyperlink.java index 90743a3de..e97a7586a 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/LSBasedHyperlink.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/LSBasedHyperlink.java @@ -22,7 +22,6 @@ import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.lsp4e.LSPEclipseUtils; @@ -46,11 +45,11 @@ public LSBasedHyperlink(Either location, IRegion highlig this.locationType = locationType; } - public LSBasedHyperlink(@NonNull Location location, IRegion linkRegion, String locationType) { + public LSBasedHyperlink(Location location, IRegion linkRegion, String locationType) { this(Either.forLeft(location), linkRegion, locationType); } - public LSBasedHyperlink(@NonNull LocationLink locationLink, IRegion linkRegion, String locationType) { + public LSBasedHyperlink(LocationLink locationLink, IRegion linkRegion, String locationType) { this(Either.forRight(locationLink), linkRegion, locationType); } @@ -70,8 +69,6 @@ public String getHyperlinkText() { } /** - * - * @return * @noreference test only */ public Either getLocation() { @@ -88,17 +85,15 @@ public void open() { } private String getLabel() { - if (this.location != null) { - String uri = this.location.isLeft() ? this.location.getLeft().getUri() : this.location.getRight().getTargetUri(); - if (uri != null) { - if (uri.startsWith(LSPEclipseUtils.FILE_URI) && uri.length() > LSPEclipseUtils.FILE_URI.length()) { - return getFileBasedLabel(uri); - } - else if (uri.startsWith(LSPEclipseUtils.INTRO_URL)) { - return getIntroUrlBasedLabel(uri); - } - return getGenericUriBasedLabel(uri); + String uri = this.location.isLeft() ? this.location.getLeft().getUri() : this.location.getRight().getTargetUri(); + if (uri != null) { + if (uri.startsWith(LSPEclipseUtils.FILE_URI) && uri.length() > LSPEclipseUtils.FILE_URI.length()) { + return getFileBasedLabel(uri); } + else if (uri.startsWith(LSPEclipseUtils.INTRO_URL)) { + return getIntroUrlBasedLabel(uri); + } + return getGenericUriBasedLabel(uri); } return locationType; @@ -113,8 +108,7 @@ private String getIntroUrlBasedLabel(String uri) { return locationType + DASH_SEPARATOR + label; } } - } - catch (Exception e) { + } catch (Exception e) { LanguageServerPlugin.logError(e.getMessage(), e); } @@ -129,7 +123,7 @@ private String getFileBasedLabel(String uriStr) { URI uri = URI.create(uriStr); IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); IFile[] files = workspaceRoot.findFilesForLocationURI(uri); - if (files != null && files.length == 1 && files[0].getProject() != null) { + if (files.length == 1 && files[0].getProject() != null) { IFile file = files[0]; IPath containerPath = file.getParent().getProjectRelativePath(); return locationType + DASH_SEPARATOR + file.getName() + DASH_SEPARATOR + file.getProject().getName() diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/OpenDeclarationHyperlinkDetector.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/OpenDeclarationHyperlinkDetector.java index 000631143..f20d1d66f 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/OpenDeclarationHyperlinkDetector.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/OpenDeclarationHyperlinkDetector.java @@ -22,6 +22,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -44,7 +46,7 @@ public class OpenDeclarationHyperlinkDetector extends AbstractHyperlinkDetector { @Override - public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { + public IHyperlink @Nullable [] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { final IDocument document = textViewer.getDocument(); if (document == null) { return null; @@ -97,7 +99,7 @@ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boo * the LSP locations */ private static Collection toHyperlinks(IDocument document, IRegion region, - String locationType, Either, List> locations) { + String locationType, @NonNullByDefault({}) Either, List> locations) { if (locations == null) { return Collections.emptyList(); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/package-info.java new file mode 100644 index 000000000..76eb1eb96 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/declaration/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.declaration; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/DiagnosticAnnotation.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/DiagnosticAnnotation.java index 687a8aebe..1f5fa337a 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/DiagnosticAnnotation.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/DiagnosticAnnotation.java @@ -11,6 +11,7 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.diagnostics; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.source.Annotation; import org.eclipse.lsp4j.Diagnostic; @@ -33,7 +34,7 @@ public String getType() { } @Override - public void setType(String type) { + public void setType(@Nullable String type) { throw new UnsupportedOperationException(); } @@ -43,7 +44,7 @@ public String getText() { } @Override - public void setText(String text) { + public void setText(@Nullable String text) { throw new UnsupportedOperationException(); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/LSPDiagnosticsToMarkers.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/LSPDiagnosticsToMarkers.java index 062d1aab9..140371370 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/LSPDiagnosticsToMarkers.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/LSPDiagnosticsToMarkers.java @@ -34,7 +34,6 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -57,17 +56,17 @@ public class LSPDiagnosticsToMarkers implements Consumer markerAttributeComputer; - public LSPDiagnosticsToMarkers(@NonNull String serverId, @Nullable String markerType, @Nullable IMarkerAttributeComputer markerAttributeComputer) { + public LSPDiagnosticsToMarkers(String serverId, @Nullable String markerType, @Nullable IMarkerAttributeComputer markerAttributeComputer) { this.languageServerId = serverId; this.markerType = markerType != null ? markerType : LS_DIAGNOSTIC_MARKER_TYPE; this.markerAttributeComputer = Optional.ofNullable(markerAttributeComputer); } - public LSPDiagnosticsToMarkers(@NonNull String serverId) { + public LSPDiagnosticsToMarkers(String serverId) { this(serverId, null, null); } @@ -79,7 +78,7 @@ public LSPDiagnosticsToMarkers(@NonNull String serverId) { * @deprecated */ @Deprecated - public LSPDiagnosticsToMarkers(IProject project, @NonNull String serverId) { + public LSPDiagnosticsToMarkers(IProject project, String serverId) { this(serverId); } @@ -105,7 +104,7 @@ public void accept(PublishDiagnosticsParams diagnostics) { } } - private void updateEditorAnnotations(@NonNull ISourceViewer sourceViewer, PublishDiagnosticsParams diagnostics) { + private void updateEditorAnnotations(ISourceViewer sourceViewer, PublishDiagnosticsParams diagnostics) { IAnnotationModel annotationModel = sourceViewer.getAnnotationModel(); if (annotationModel == null) { return; @@ -134,12 +133,12 @@ private void updateEditorAnnotations(@NonNull ISourceViewer sourceViewer, Publis private WorkspaceJob updateMarkers(PublishDiagnosticsParams diagnostics, IResource resource) { WorkspaceJob job = new WorkspaceJob("Update markers from diagnostics") { //$NON-NLS-1$ @Override - public boolean belongsTo(Object family) { + public boolean belongsTo(@Nullable Object family) { return LanguageServerPlugin.FAMILY_UPDATE_MARKERS == family; } @Override - public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + public IStatus runInWorkspace(@Nullable IProgressMonitor monitor) throws CoreException { if (!resource.exists()) { return Status.OK_STATUS; } @@ -203,7 +202,7 @@ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { return job; } - protected void updateMarker(@NonNull Map targetAttributes, @NonNull IMarker marker) { + protected void updateMarker(Map targetAttributes, IMarker marker) { try { if (!targetAttributes.equals(marker.getAttributes())) { marker.setAttributes(targetAttributes); @@ -213,7 +212,7 @@ protected void updateMarker(@NonNull Map targetAttributes, @NonN } } - private IMarker getExistingMarkerFor(IDocument document, Diagnostic diagnostic, Set remainingMarkers) { + private @Nullable IMarker getExistingMarkerFor(@Nullable IDocument document, Diagnostic diagnostic, Set remainingMarkers) { if (document == null) { return null; } @@ -236,14 +235,11 @@ private IMarker getExistingMarkerFor(IDocument document, Diagnostic diagnostic, return null; } - private @NonNull Map computeMarkerAttributes(@Nullable IDocument document, - @NonNull Diagnostic diagnostic, @NonNull IResource resource) { + private Map computeMarkerAttributes(@Nullable IDocument document, + Diagnostic diagnostic, IResource resource) { Either code = diagnostic.getCode(); if (code != null && code.isLeft()) { - String left = code.getLeft(); - if (left != null) { - diagnostic.setCode(Either.forLeft(left.intern())); - } + diagnostic.setCode(Either.forLeft(code.getLeft().intern())); } String source = diagnostic.getSource(); if (source != null) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/package-info.java new file mode 100644 index 000000000..44c072a3c --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/diagnostics/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.diagnostics; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/DocumentLinkDetector.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/DocumentLinkDetector.java index cdfc87aed..e44ad4ef4 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/DocumentLinkDetector.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/DocumentLinkDetector.java @@ -19,6 +19,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -69,7 +70,7 @@ public void open() { } @Override - public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { + public IHyperlink @Nullable [] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { final IDocument document = textViewer.getDocument(); if (document == null) { return null; @@ -106,7 +107,7 @@ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boo } } - private DocumentHyperlink toHyperlink(IRegion region, final IDocument document, DocumentLink link) { + private @Nullable DocumentHyperlink toHyperlink(IRegion region, final IDocument document, DocumentLink link) { DocumentHyperlink jfaceLink = null; try { int start = LSPEclipseUtils.toOffset(link.getRange().getStart(), document); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/LSPDocumentLinkPresentationReconcilingStrategy.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/LSPDocumentLinkPresentationReconcilingStrategy.java index b9c449830..48af0b91a 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/LSPDocumentLinkPresentationReconcilingStrategy.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/LSPDocumentLinkPresentationReconcilingStrategy.java @@ -44,11 +44,11 @@ public class LSPDocumentLinkPresentationReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, ITextViewerLifecycle { /** The target viewer. */ - private ITextViewer viewer; + private @Nullable ITextViewer viewer; - private CompletableFuture request; + private @Nullable CompletableFuture request; - private IDocument document; + private @Nullable IDocument document; @Override public void install(@Nullable ITextViewer viewer) { @@ -87,8 +87,9 @@ private void underline() { } } - private void underline(List links) { - if (document == null || links == null) { + private void underline(@Nullable List links) { + final var viewer = this.viewer; + if (document == null || links == null || viewer == null) { return; } for (DocumentLink link : links) { @@ -147,12 +148,12 @@ private void cancel() { } @Override - public void setDocument(IDocument document) { + public void setDocument(@Nullable IDocument document) { this.document = document; } @Override - public void setProgressMonitor(IProgressMonitor monitor) { + public void setProgressMonitor(@Nullable IProgressMonitor monitor) { // Do nothing } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/package-info.java new file mode 100644 index 000000000..e6d7f7652 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/documentLink/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.documentLink; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/LSPFoldingReconcilingStrategy.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/LSPFoldingReconcilingStrategy.java index 76860452a..484071b61 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/LSPFoldingReconcilingStrategy.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/LSPFoldingReconcilingStrategy.java @@ -10,6 +10,8 @@ */ package org.eclipse.lsp4e.operations.folding; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull; + import java.net.URI; import java.util.ArrayList; import java.util.Collections; @@ -21,7 +23,7 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -58,10 +60,10 @@ public class LSPFoldingReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, IProjectionListener, ITextViewerLifecycle { - private IDocument document; - private ProjectionAnnotationModel projectionAnnotationModel; - private ProjectionViewer viewer; - private @NonNull List>> requests = List.of(); + private @Nullable IDocument document; + private @Nullable ProjectionAnnotationModel projectionAnnotationModel; + private @Nullable ProjectionViewer viewer; + private List>> requests = List.of(); private volatile long timestamp = 0; private final boolean collapseImports; @@ -127,13 +129,13 @@ public void markCollapsed() { } @Override - public void reconcile(IRegion subRegion) { - IDocument theDocument = document; - if (projectionAnnotationModel == null || theDocument == null) { + public void reconcile(@Nullable IRegion subRegion) { + final var document = this.document; + if (projectionAnnotationModel == null || document == null) { return; } - URI uri = LSPEclipseUtils.toUri(theDocument); + URI uri = LSPEclipseUtils.toUri(document); if (uri == null) { return; } @@ -141,12 +143,13 @@ public void reconcile(IRegion subRegion) { final var params = new FoldingRangeRequestParams(identifier); // cancel previous requests requests.forEach(request -> request.cancel(true)); - requests = LanguageServers.forDocument(theDocument).withCapability(ServerCapabilities::getFoldingRangeProvider) + requests = LanguageServers.forDocument(document) + .withCapability(ServerCapabilities::getFoldingRangeProvider) .computeAll(server -> server.getTextDocumentService().foldingRange(params)); requests.forEach(ranges -> ranges.thenAccept(this::applyFolding)); } - private void applyFolding(List ranges) { + private void applyFolding(@Nullable List ranges) { // these are what are passed off to the annotation model to // actually create and maintain the annotations final var deletions = new ArrayList(); @@ -188,8 +191,8 @@ public void install(ITextViewer viewer) { } if (viewer instanceof ProjectionViewer projViewer) { this.viewer = projViewer; - this.viewer.addProjectionListener(this); - this.projectionAnnotationModel = this.viewer.getProjectionAnnotationModel(); + projViewer.addProjectionListener(this); + this.projectionAnnotationModel = projViewer.getProjectionAnnotationModel(); } } @@ -204,7 +207,7 @@ public void uninstall() { } @Override - public void setDocument(IDocument document) { + public void setDocument(@Nullable IDocument document) { this.document = document; } @@ -237,9 +240,10 @@ public void projectionEnabled() { * the end line number * @throws BadLocationException */ - private void updateAnnotation(List deletions, - List existing, Map additions, int line, Integer endLineNumber, boolean collapsedByDefault) + private void updateAnnotation(List deletions, List existing, + Map additions, int line, Integer endLineNumber, boolean collapsedByDefault) throws BadLocationException { + final var document = castNonNull(this.document); int startOffset = document.getLineOffset(line); int endOffset = document.getLineOffset(endLineNumber) + document.getLineLength(endLineNumber); final var newPos = new Position(startOffset, endOffset - startOffset); @@ -263,7 +267,7 @@ private void updateAnnotation(List deletions, * @param deletions * the list of annotations to be deleted */ - protected void updateAnnotations(Annotation existingAnnotation, Position newPos, List deletions) { + protected void updateAnnotations(Annotation existingAnnotation, @Nullable Position newPos, List deletions) { if (existingAnnotation instanceof FoldingAnnotation foldingAnnotation) { // if a new position can be calculated then update the position of // the annotation, @@ -296,16 +300,18 @@ protected void updateAnnotations(Annotation existingAnnotation, Position newPos, */ protected void markInvalidAnnotationsForDeletion(List deletions, List existing) { + final var projectionAnnotationModel = this.projectionAnnotationModel; + if (projectionAnnotationModel == null) + return; Iterator iter = projectionAnnotationModel.getAnnotationIterator(); if (iter != null) { while (iter.hasNext()) { - Annotation anno = iter.next(); - if (anno instanceof FoldingAnnotation folding) { - Position pos = projectionAnnotationModel.getPosition(anno); + if (iter.next() instanceof FoldingAnnotation foldingAnno) { + Position pos = projectionAnnotationModel.getPosition(foldingAnno); if (pos.length == 0) { - deletions.add(folding); + deletions.add(foldingAnno); } else { - existing.add(folding); + existing.add(foldingAnno); } } } @@ -324,7 +330,7 @@ public void reconcile(DirtyRegion dirtyRegion, IRegion partition) { } @Override - public void setProgressMonitor(IProgressMonitor monitor) { + public void setProgressMonitor(@Nullable IProgressMonitor monitor) { // Do nothing } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/package-info.java new file mode 100644 index 000000000..47e753b2e --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/folding/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.folding; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatFilesHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatFilesHandler.java index 595ff38bc..b471023a6 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatFilesHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatFilesHandler.java @@ -30,10 +30,11 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.e4.core.commands.ExpressionContext; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.TextSelection; @@ -53,9 +54,12 @@ public class LSPFormatFilesHandler extends AbstractHandler { protected final LSPFormatter formatter = new LSPFormatter(); @Override - public Object execute(final ExecutionEvent event) throws ExecutionException { + public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException { if (event.getApplicationContext() instanceof final ExpressionContext ctx) { final var job = Job.create(Messages.LSPFormatFilesHandler_FormattingSelectedFiles, monitor -> { + if (monitor == null) + monitor = new NullProgressMonitor(); + final var selectedFiles = getSelectedFiles(ctx); final var subMonitor = SubMonitor.convert(monitor, selectedFiles.size()); for (final IFile file : selectedFiles) { @@ -73,7 +77,7 @@ public Object execute(final ExecutionEvent event) throws ExecutionException { return null; } - protected void formatFile(final @NonNull IFile file, final IProgressMonitor monitor) { + protected void formatFile(final IFile file, final IProgressMonitor monitor) { if (!file.exists() || !LanguageServersRegistry.getInstance().canUseLanguageServer(file)) return; @@ -122,12 +126,12 @@ protected void saveDocument(IDocumentProvider docProvider, IFile file, IProgress } } - protected Set<@NonNull IFile> getSelectedFiles(final ExpressionContext ctx) { + protected Set getSelectedFiles(final ExpressionContext ctx) { final var selection = getSelection(ctx); if (selection.isEmpty()) return Collections.emptySet(); - final var files = new HashSet<@NonNull IFile>(); + final var files = new HashSet(); for (final var item : selection) { try { if (item instanceof final IResource resource) { @@ -164,7 +168,7 @@ protected Collection getSelection(final ExpressionContext ctx) { } @Override - public void setEnabled(final Object evaluationContext) { + public void setEnabled(final @Nullable Object evaluationContext) { if (evaluationContext instanceof ExpressionContext ctx) { final var selection = getSelection(ctx); if (selection.isEmpty()) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatHandler.java index ef1f29b88..6833d6dd0 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatHandler.java @@ -16,6 +16,7 @@ import java.util.ConcurrentModificationException; import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; @@ -66,7 +67,7 @@ protected void execute(ExecutionEvent event, ITextEditor textEditor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(LSPFormatter::supportsFormatting, this::hasSelection); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatter.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatter.java index 7e010d354..9dc3a3445 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatter.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatter.java @@ -17,7 +17,6 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -38,7 +37,7 @@ import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; public class LSPFormatter { - public CompletableFuture> requestFormatting(@NonNull IDocument document, @NonNull ITextSelection textSelection) throws BadLocationException { + public CompletableFuture> requestFormatting(IDocument document, ITextSelection textSelection) throws BadLocationException { URI uri = LSPEclipseUtils.toUri(document); if (uri == null) { return CompletableFuture.completedFuture(Optional.empty()); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/package-info.java new file mode 100644 index 000000000..baf4b0b95 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.format; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/HighlightReconcilingStrategy.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/HighlightReconcilingStrategy.java index 3d99a6904..9245dc42b 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/HighlightReconcilingStrategy.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/HighlightReconcilingStrategy.java @@ -13,6 +13,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.highlight; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.lateNonNull; + import java.net.URI; import java.util.HashMap; import java.util.Iterator; @@ -27,7 +29,6 @@ import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -73,19 +74,18 @@ public class HighlightReconcilingStrategy public static final String TEXT_ANNOTATION_TYPE = "org.eclipse.lsp4e.text"; //$NON-NLS-1$ private boolean enabled; - private ISourceViewer sourceViewer; - private IDocument document; - - private Job highlightJob; + private @Nullable ISourceViewer sourceViewer; + private @Nullable IDocument document; + private @Nullable Job highlightJob; /** * Holds the current occurrence annotations. */ - private Annotation[] fOccurrenceAnnotations = null; + private Annotation @Nullable [] fOccurrenceAnnotations = null; class EditorSelectionChangedListener implements ISelectionChangedListener { - public void install(ISelectionProvider selectionProvider) { + public void install(@Nullable ISelectionProvider selectionProvider) { if (selectionProvider == null) return; @@ -96,7 +96,7 @@ public void install(ISelectionProvider selectionProvider) { } } - public void uninstall(ISelectionProvider selectionProvider) { + public void uninstall(@Nullable ISelectionProvider selectionProvider) { if (selectionProvider == null) return; @@ -124,9 +124,9 @@ private void updateHighlights(ISelection selection) { } } - private EditorSelectionChangedListener editorSelectionChangedListener; + private EditorSelectionChangedListener editorSelectionChangedListener = lateNonNull(); - private @NonNull List<@NonNull CompletableFuture<@Nullable List>> requests = List.of(); + private List>> requests = List.of(); @Override public void install(ITextViewer viewer) { @@ -136,7 +136,7 @@ public void install(ITextViewer viewer) { this.enabled = preferences.getBoolean(TOGGLE_HIGHLIGHT_PREFERENCE, true); this.sourceViewer = thisSourceViewer; editorSelectionChangedListener = new EditorSelectionChangedListener(); - editorSelectionChangedListener.install(sourceViewer.getSelectionProvider()); + editorSelectionChangedListener.install(thisSourceViewer.getSelectionProvider()); } } @@ -152,16 +152,16 @@ public void uninstall() { } @Override - public void setProgressMonitor(IProgressMonitor monitor) { - + public void setProgressMonitor(@Nullable IProgressMonitor monitor) { } @Override public void initialReconcile() { + final var sourceViewer = this.sourceViewer; if (sourceViewer != null) { ISelectionProvider selectionProvider = sourceViewer.getSelectionProvider(); final StyledText textWidget = sourceViewer.getTextWidget(); - if (textWidget != null && selectionProvider != null) { + if (textWidget != null) { textWidget.getDisplay().asyncExec(() -> { if (!textWidget.isDisposed()) { updateHighlights(selectionProvider.getSelection()); @@ -172,7 +172,7 @@ public void initialReconcile() { } @Override - public void setDocument(IDocument document) { + public void setDocument(@Nullable IDocument document) { this.document = document; } @@ -183,8 +183,10 @@ public void setDocument(IDocument document) { * @param caretOffset * @param monitor */ - private void collectHighlights(int caretOffset, IProgressMonitor monitor) { - if (sourceViewer == null || !enabled || monitor.isCanceled()) { + private void collectHighlights(int caretOffset, @Nullable IProgressMonitor monitor) { + final var sourceViewer = this.sourceViewer; + final var document = this.document; + if (sourceViewer == null || document == null || !enabled || monitor != null && monitor.isCanceled()) { return; } cancel(); @@ -196,15 +198,16 @@ private void collectHighlights(int caretOffset, IProgressMonitor monitor) { return; } URI uri = LSPEclipseUtils.toUri(document); - if(uri == null) { + if (uri == null) { return; } final var identifier = LSPEclipseUtils.toTextDocumentIdentifier(uri); final var params = new DocumentHighlightParams(identifier, position); - requests = LanguageServers.forDocument(document).withCapability(ServerCapabilities::getDocumentHighlightProvider) + requests = LanguageServers.forDocument(document) + .withCapability(ServerCapabilities::getDocumentHighlightProvider) .computeAll(languageServer -> languageServer.getTextDocumentService().documentHighlight(params)); requests.forEach(request -> request.thenAcceptAsync(highlights -> { - if (!monitor.isCanceled()) { + if (monitor == null || !monitor.isCanceled()) { updateAnnotations(highlights, sourceViewer.getAnnotationModel()); } })); @@ -226,20 +229,19 @@ private void cancel() { * annotation model to update. */ private void updateAnnotations(@Nullable List highlights, IAnnotationModel annotationModel) { - if (highlights == null) + final var document = this.document; + if (highlights == null || document == null) return; final var annotationMap = new HashMap(highlights.size()); for (DocumentHighlight h : highlights) { - if (h != null) { - try { - int start = LSPEclipseUtils.toOffset(h.getRange().getStart(), document); - int end = LSPEclipseUtils.toOffset(h.getRange().getEnd(), document); - annotationMap.put(new Annotation(kindToAnnotationType(h.getKind()), false, null), - new org.eclipse.jface.text.Position(start, end - start)); - } catch (BadLocationException e) { - LanguageServerPlugin.logError(e); - } + try { + int start = LSPEclipseUtils.toOffset(h.getRange().getStart(), document); + int end = LSPEclipseUtils.toOffset(h.getRange().getEnd(), document); + annotationMap.put(new Annotation(kindToAnnotationType(h.getKind()), false, null), + new org.eclipse.jface.text.Position(start, end - start)); + } catch (Exception e) { + LanguageServerPlugin.logError(e); } } @@ -275,7 +277,12 @@ private Object getLockObject(IAnnotationModel annotationModel) { } void removeOccurrenceAnnotations() { + final var sourceViewer = this.sourceViewer; + if(sourceViewer == null) + return; + IAnnotationModel annotationModel = sourceViewer.getAnnotationModel(); + final var fOccurrenceAnnotations = this.fOccurrenceAnnotations; if (annotationModel == null || fOccurrenceAnnotations == null) return; @@ -286,7 +293,7 @@ void removeOccurrenceAnnotations() { for (Annotation fOccurrenceAnnotation : fOccurrenceAnnotations) annotationModel.removeAnnotation(fOccurrenceAnnotation); } - fOccurrenceAnnotations = null; + this.fOccurrenceAnnotations = null; } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/package-info.java new file mode 100644 index 000000000..faf1dfd2d --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/highlight/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.highlight; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/FocusableBrowserInformationControl.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/FocusableBrowserInformationControl.java index e582bc3e5..875d080ba 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/FocusableBrowserInformationControl.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/FocusableBrowserInformationControl.java @@ -15,7 +15,6 @@ import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Platform; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.internal.text.html.BrowserInformationControl; import org.eclipse.jface.resource.ColorRegistry; @@ -70,7 +69,7 @@ public FocusableBrowserInformationControl(Shell parent) { super(parent, JFaceResources.DEFAULT_FONT, EditorsUI.getTooltipAffordanceString()); } - private double adjust(double height, Object margin) { + private double adjust(double height, @Nullable Object margin) { if (margin instanceof String marginString && marginString.endsWith("px")) { //$NON-NLS-1$ try { height += Integer.parseInt(marginString.substring(0, marginString.length() - 2)); @@ -124,7 +123,7 @@ protected void createContent(Composite parent) { b.setJavascriptEnabled(true); } - private static Object safeEvaluate(Browser browser, String expression) { + private static @Nullable Object safeEvaluate(Browser browser, String expression) { try { return browser.evaluate(expression); } catch (Exception ex) { @@ -143,7 +142,7 @@ private static boolean safeExecute(Browser browser, String expression) { } @Override - public void setInput(Object input) { + public void setInput(@Nullable Object input) { if (input instanceof String html) { input = styleHtml(html); } @@ -151,7 +150,7 @@ public void setInput(Object input) { } public String styleHtml(String html) { - if (html == null || html.isEmpty()) { + if (html.isEmpty()) { return html; } @@ -199,7 +198,7 @@ private boolean isDarkTheme() { return (color.red * 0.299 + color.green * 0.587+ color.blue *0.114) < 128; //turn to grey and check the level } - private static @NonNull CharSequence toHTMLrgb(RGB rgb) { + private static CharSequence toHTMLrgb(RGB rgb) { final var builder = new StringBuilder(7); builder.append('#'); appendAsHexString(builder, rgb.red); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/LSPTextHover.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/LSPTextHover.java index c34d8e5c0..1933ffe3f 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/LSPTextHover.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/LSPTextHover.java @@ -15,6 +15,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.hover; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull; + import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -24,7 +26,6 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.internal.text.html.BrowserInformationControl; import org.eclipse.jface.text.AbstractReusableInformationControlCreator; @@ -61,39 +62,31 @@ public class LSPTextHover implements ITextHover, ITextHoverExtension { private static final MarkupParser MARKDOWN_PARSER = new MarkupParser(new MarkdownLanguage(true)); private static final int GET_TIMEOUT_MS = 1000; - private IRegion lastRegion; - private ITextViewer lastViewer; - private CompletableFuture<@NonNull List<@NonNull Hover>> request; + private @Nullable IRegion lastRegion; + private @Nullable ITextViewer lastViewer; + private @Nullable CompletableFuture> request; @Override - public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { - if (textViewer == null || hoverRegion == null) { - return null; - } - CompletableFuture hoverInfoFuture = getHoverInfoFuture(textViewer, hoverRegion); - if (hoverInfoFuture != null) { - try { - String result = hoverInfoFuture.get(GET_TIMEOUT_MS, TimeUnit.MILLISECONDS); - if (result != null) { - return result; - } - } catch (ExecutionException e) { - LanguageServerPlugin.logError(e); - } catch (InterruptedException e) { - LanguageServerPlugin.logError(e); - Thread.currentThread().interrupt(); - } catch (TimeoutException e) { - LanguageServerPlugin.logWarning("Could not get hover information due to timeout after " + GET_TIMEOUT_MS + " milliseconds", e); //$NON-NLS-1$ //$NON-NLS-2$ - } + public @Nullable String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + CompletableFuture<@Nullable String> hoverInfoFuture = getHoverInfoFuture(textViewer, hoverRegion); + try { + return hoverInfoFuture.get(GET_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (ExecutionException e) { + LanguageServerPlugin.logError(e); + } catch (InterruptedException e) { + LanguageServerPlugin.logError(e); + Thread.currentThread().interrupt(); + } catch (TimeoutException e) { + LanguageServerPlugin.logWarning("Could not get hover information due to timeout after " + GET_TIMEOUT_MS + " milliseconds", e); //$NON-NLS-1$ //$NON-NLS-2$ } return null; } - public CompletableFuture getHoverInfoFuture(@NonNull ITextViewer textViewer, @NonNull IRegion hoverRegion) { + public CompletableFuture<@Nullable String> getHoverInfoFuture(ITextViewer textViewer, IRegion hoverRegion) { if (this.request == null || !textViewer.equals(this.lastViewer) || !hoverRegion.equals(this.lastRegion)) { initiateHoverRequest(textViewer, hoverRegion.getOffset()); } - return request.thenApply(hoversList -> { + return castNonNull(request).thenApply(hoversList -> { String result = hoversList.stream() .filter(Objects::nonNull) .map(LSPTextHover::getHoverString) @@ -108,11 +101,11 @@ public CompletableFuture getHoverInfoFuture(@NonNull ITextViewer textVie }); } - protected static @Nullable String getHoverString(@NonNull Hover hover) { + protected static @Nullable String getHoverString(Hover hover) { Either>, MarkupContent> hoverContent = hover.getContents(); if (hoverContent.isLeft()) { List> contents = hoverContent.getLeft(); - if (contents == null || contents.isEmpty()) { + if (contents.isEmpty()) { return null; } return contents.stream().map(content -> { @@ -140,11 +133,9 @@ public CompletableFuture getHoverInfoFuture(@NonNull ITextViewer textVie @Override public @Nullable IRegion getHoverRegion(ITextViewer textViewer, int offset) { - if (textViewer == null) { - return null; - } - if (this.request == null || this.lastRegion == null || !textViewer.equals(this.lastViewer) - || offset < this.lastRegion.getOffset() || offset > lastRegion.getOffset() + lastRegion.getLength()) { + final var lastRegion = this.lastRegion; + if (this.request == null || lastRegion == null || !textViewer.equals(this.lastViewer) + || offset < lastRegion.getOffset() || offset > lastRegion.getOffset() + lastRegion.getLength()) { initiateHoverRequest(textViewer, offset); } try { @@ -155,7 +146,7 @@ public CompletableFuture getHoverInfoFuture(@NonNull ITextViewer textVie boolean[] oneHoverAtLeast = new boolean[] { false }; int[] regionStartOffset = new int[] { 0 }; int[] regionEndOffset = new int[] { document.getLength() }; - this.request.get(GET_TIMEOUT_MS, TimeUnit.MILLISECONDS).stream() + castNonNull(this.request).get(GET_TIMEOUT_MS, TimeUnit.MILLISECONDS).stream() .filter(Objects::nonNull) .map(Hover::getRange) .filter(Objects::nonNull) @@ -195,7 +186,7 @@ public CompletableFuture getHoverInfoFuture(@NonNull ITextViewer textVie * @param offset * the hovered offset. */ - private void initiateHoverRequest(@NonNull ITextViewer viewer, int offset) { + private void initiateHoverRequest(ITextViewer viewer, int offset) { final IDocument document = viewer.getDocument(); if (document == null) { return; @@ -213,7 +204,7 @@ private void initiateHoverRequest(@NonNull ITextViewer viewer, int offset) { } @Override - public IInformationControlCreator getHoverControlCreator() { + public @Nullable IInformationControlCreator getHoverControlCreator() { return new AbstractReusableInformationControlCreator() { @Override protected IInformationControl doCreateInformationControl(Shell parent) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/package-info.java new file mode 100644 index 000000000..46a8f2c04 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/hover/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.hover; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/InlayHintProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/InlayHintProvider.java index c1f76175c..188c9f9fe 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/InlayHintProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/InlayHintProvider.java @@ -16,7 +16,7 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; @@ -34,7 +34,7 @@ public class InlayHintProvider extends AbstractCodeMiningProvider { - private CompletableFuture> provideCodeMinings(@NonNull IDocument document) { + private @Nullable CompletableFuture> provideCodeMinings(IDocument document) { URI docURI = LSPEclipseUtils.toUri(document); if (docURI != null) { // Eclipse seems to request minings only when the document is loaded (or changed), rather than @@ -63,8 +63,8 @@ private CompletableFuture> provideCodeMinings(@NonNu } } - private LSPLineContentCodeMining toCodeMining(@NonNull IDocument document, @NonNull LanguageServerWrapper languageServerWrapper, - @NonNull InlayHint inlayHint) { + private @Nullable LSPLineContentCodeMining toCodeMining(IDocument document, LanguageServerWrapper languageServerWrapper, + InlayHint inlayHint) { try { return new LSPLineContentCodeMining(inlayHint, document, languageServerWrapper, InlayHintProvider.this); } catch (BadLocationException e) { @@ -74,7 +74,7 @@ private LSPLineContentCodeMining toCodeMining(@NonNull IDocument document, @NonN } @Override - public CompletableFuture> provideCodeMinings(ITextViewer viewer, + public @Nullable CompletableFuture> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) { IDocument document = viewer.getDocument(); return document != null ? provideCodeMinings(document) : null; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java index b7d2d5e9d..4291d589f 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java @@ -17,7 +17,6 @@ import java.util.stream.Collectors; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -49,13 +48,13 @@ public class LSPLineContentCodeMining extends LineContentCodeMining { private InlayHint inlayHint; - private final @NonNull LanguageServerWrapper wrapper; - private final @NonNull IDocument document; + private final LanguageServerWrapper wrapper; + private final IDocument document; - private Point location; - private FontData[] fontData; + private @Nullable Point location; + private FontData @Nullable [] fontData; - public LSPLineContentCodeMining(@NonNull InlayHint inlayHint, @NonNull IDocument document, @NonNull LanguageServerWrapper languageServerWrapper, + public LSPLineContentCodeMining(InlayHint inlayHint, IDocument document, LanguageServerWrapper languageServerWrapper, InlayHintProvider provider) throws BadLocationException { super(toPosition(inlayHint.getPosition(), document), provider); this.inlayHint = inlayHint; @@ -65,15 +64,15 @@ public LSPLineContentCodeMining(@NonNull InlayHint inlayHint, @NonNull IDocument } @Override - public void setLabel(final String label) { + public void setLabel(final @Nullable String label) { if (label == null || label.isEmpty() || Character.isWhitespace(label.charAt(label.length() - 1))) super.setLabel(label); else super.setLabel(label + " "); //$NON-NLS-1$ } - protected static @Nullable String getInlayHintString(@NonNull InlayHint inlayHint) { - Either> label = inlayHint.getLabel(); + protected static @Nullable String getInlayHintString(InlayHint inlayHint) { + Either> label = inlayHint.getLabel(); return label.map(Function.identity(), (parts) -> { if (parts == null) { return null; @@ -122,11 +121,11 @@ private static org.eclipse.jface.text.Position toPosition(Position position, IDo } @Override - public final Consumer getAction() { - return inlayHint.getLabel().map(l -> null, r -> labelPartAction(r)); + public final @Nullable Consumer getAction() { + return inlayHint.getLabel().map(l -> null, this::labelPartAction); } - private Consumer labelPartAction(List labelParts) { + private @Nullable Consumer labelPartAction(List labelParts) { String title = getLabel(); if (title != null && !title.isEmpty() && labelParts.stream().map(InlayHintLabelPart::getCommand).anyMatch(Objects::nonNull)) { return me -> { @@ -154,6 +153,7 @@ private Optional findLabelPart(MouseEvent me, List> request; + private @Nullable CompletableFuture> request; protected boolean fEnabled; protected void install() { @@ -49,7 +49,7 @@ protected void uninstall() { cancel(); } - protected CompletableFuture> collectLinkedEditingRanges(IDocument document, int offset) { + protected CompletableFuture> collectLinkedEditingRanges(@Nullable IDocument document, int offset) { cancel(); if (document == null) { @@ -68,7 +68,7 @@ protected CompletableFuture> collectLinkedEditingR } } - private boolean rangesContainOffset(@NonNull LinkedEditingRanges ranges, int offset, IDocument document) { + private boolean rangesContainOffset(LinkedEditingRanges ranges, int offset, IDocument document) { for (Range range : ranges.getRanges()) { if (LSPEclipseUtils.isOffsetInRange(offset, range, document)) { return true; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/LSPLinkedEditingReconcilingStrategy.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/LSPLinkedEditingReconcilingStrategy.java index 28a3656f6..14c3180ce 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/LSPLinkedEditingReconcilingStrategy.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/LSPLinkedEditingReconcilingStrategy.java @@ -11,6 +11,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.linkedediting; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull; + import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,7 +21,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -53,14 +55,14 @@ public class LSPLinkedEditingReconcilingStrategy extends LSPLinkedEditingBase implements IReconcilingStrategy, IReconcilingStrategyExtension, ITextViewerLifecycle { - private ISourceViewer sourceViewer; - private IDocument fDocument; - private EditorSelectionChangedListener editorSelectionChangedListener; - private Job highlightJob; - private LinkedModeModel linkedModel; - - class EditorSelectionChangedListener implements ISelectionChangedListener { - public void install(ISelectionProvider selectionProvider) { + private @Nullable ISourceViewer sourceViewer; + private @Nullable IDocument document; + private @Nullable EditorSelectionChangedListener editorSelectionChangedListener; + private @Nullable Job highlightJob; + private @Nullable LinkedModeModel linkedModel; + + private final class EditorSelectionChangedListener implements ISelectionChangedListener { + public void install(@Nullable ISelectionProvider selectionProvider) { if (selectionProvider == null) return; @@ -71,7 +73,7 @@ public void install(ISelectionProvider selectionProvider) { } } - public void uninstall(ISelectionProvider selectionProvider) { + public void uninstall(@Nullable ISelectionProvider selectionProvider) { if (selectionProvider == null) return; @@ -94,13 +96,13 @@ public void install(ITextViewer viewer) { super.install(); this.sourceViewer = thisViewer; editorSelectionChangedListener = new EditorSelectionChangedListener(); - editorSelectionChangedListener.install(sourceViewer.getSelectionProvider()); + editorSelectionChangedListener.install(thisViewer.getSelectionProvider()); } } @Override public void uninstall() { - if (sourceViewer != null) { + if (sourceViewer != null && editorSelectionChangedListener != null) { editorSelectionChangedListener.uninstall(sourceViewer.getSelectionProvider()); } super.uninstall(); @@ -119,11 +121,12 @@ public void preferenceChange(PreferenceChangeEvent event) { } @Override - public void setProgressMonitor(IProgressMonitor monitor) { + public void setProgressMonitor(@Nullable IProgressMonitor monitor) { } @Override public void initialReconcile() { + final var sourceViewer = this.sourceViewer; if (sourceViewer != null) { ISelectionProvider selectionProvider = sourceViewer.getSelectionProvider(); final StyledText textWidget = sourceViewer.getTextWidget(); @@ -138,8 +141,8 @@ public void initialReconcile() { } @Override - public void setDocument(IDocument document) { - this.fDocument = document; + public void setDocument(@Nullable IDocument document) { + this.document = document; } @Override @@ -157,13 +160,14 @@ private void updateLinkedEditing(ISelection selection) { } private void updateLinkedEditing(int offset) { - if (sourceViewer != null && fDocument != null && fEnabled && linkedModel == null - || !linkedModel.anyPositionContains(offset)) { + final var linkedModel = this.linkedModel; + if (sourceViewer != null && document != null && fEnabled && (linkedModel == null + || !linkedModel.anyPositionContains(offset))) { if (linkedModel != null) { linkedModel.exit(ILinkedModeListener.EXIT_ALL); - linkedModel = null; + this.linkedModel = null; } - collectLinkedEditingRanges(fDocument, offset).thenAcceptAsync(optional -> { + collectLinkedEditingRanges(document, offset).thenAcceptAsync(optional -> { optional.ifPresent(this::applyLinkedEdit); }).exceptionally(e -> { if (!CancellationUtil.isRequestCancelledException(e)) { // do not report error if the server has cancelled the request @@ -174,7 +178,7 @@ private void updateLinkedEditing(int offset) { } } - private void applyLinkedEdit(LinkedEditingRanges ranges) { + private void applyLinkedEdit(@Nullable LinkedEditingRanges ranges) { if (highlightJob != null) { highlightJob.cancel(); } @@ -185,11 +189,12 @@ private void applyLinkedEdit(LinkedEditingRanges ranges) { highlightJob = new UIJob("LSP4E Linked Editing") { //$NON-NLS-1$ @Override public IStatus runInUIThread(IProgressMonitor monitor) { - linkedModel = new LinkedModeModel(); + final var linkedModel = LSPLinkedEditingReconcilingStrategy.this.linkedModel = new LinkedModeModel(); try { linkedModel.addGroup(toJFaceGroup(ranges)); linkedModel.forceInstall(); - ITextSelection selectionBefore = (ITextSelection)sourceViewer.getSelectionProvider().getSelection(); + final var sourceViewer = castNonNull(LSPLinkedEditingReconcilingStrategy.this.sourceViewer); + ITextSelection selectionBefore = (ITextSelection) sourceViewer.getSelectionProvider().getSelection(); LinkedModeUI linkedMode = new EditorLinkedModeUI(linkedModel, sourceViewer); linkedMode.setExitPolicy((model, event, offset, length) -> { if (event.character == 0 || event.character == '\b') { @@ -220,12 +225,12 @@ public IStatus runInUIThread(IProgressMonitor monitor) { highlightJob.schedule(); } - String getValueInRange(IRegion selectedRegion, VerifyEvent event, int offset, int length) { + private @Nullable String getValueInRange(IRegion selectedRegion, VerifyEvent event, int offset, int length) { if (offset < selectedRegion.getOffset() || offset > selectedRegion.getOffset() + selectedRegion.getLength()) { return null; } try { - final var sb = new StringBuilder(fDocument.get(selectedRegion.getOffset(), selectedRegion.getLength())); // The range text before the insertion + final var sb = new StringBuilder(castNonNull(document).get(selectedRegion.getOffset(), selectedRegion.getLength())); // The range text before the insertion String newChars = event.character == 0 ? "" : Character.toString(event.character); //$NON-NLS-1$ sb.replace(offset - selectedRegion.getOffset(), offset - selectedRegion.getOffset() + selectedRegion.getLength(), newChars); return sb.toString(); @@ -235,12 +240,13 @@ String getValueInRange(IRegion selectedRegion, VerifyEvent event, int offset, in return null; } - private LinkedPositionGroup toJFaceGroup(@NonNull LinkedEditingRanges ranges) throws BadLocationException { + private LinkedPositionGroup toJFaceGroup(LinkedEditingRanges ranges) throws BadLocationException { + final var document = castNonNull(this.document); final var res = new LinkedPositionGroup(); for (Range range : ranges.getRanges()) { - int startOffset = LSPEclipseUtils.toOffset(range.getStart(), fDocument); - int length = LSPEclipseUtils.toOffset(range.getEnd(), fDocument) - startOffset; - res.addPosition(new LinkedPosition(fDocument, startOffset, length)); + int startOffset = LSPEclipseUtils.toOffset(range.getStart(), document); + int length = LSPEclipseUtils.toOffset(range.getEnd(), document) - startOffset; + res.addPosition(new LinkedPosition(document, startOffset, length)); } return res; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/package-info.java new file mode 100644 index 000000000..a476701b8 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/linkedediting/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.linkedediting; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchContentProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchContentProvider.java index addb1a48b..d999a4fd9 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchContentProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchContentProvider.java @@ -13,6 +13,7 @@ import java.util.Arrays; import java.util.List; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.search.internal.ui.text.FileMatch; @@ -24,19 +25,22 @@ public class FileAndURIMatchContentProvider implements ITreeContentProvider { private final FileTreeContentProvider delegate; - private LSSearchResult searchResult; - private FileSearchResult filteredFileSearchResult; + private @Nullable LSSearchResult searchResult; + private @Nullable FileSearchResult filteredFileSearchResult; FileAndURIMatchContentProvider(FileTreeContentProvider delegate) { this.delegate = delegate; } @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + public void inputChanged(Viewer viewer, @Nullable Object oldInput, @Nullable Object newInput) { if (newInput instanceof FileSearchResult initial && initial.getQuery() instanceof FileSearchQuery query) { - this.filteredFileSearchResult = new FileSearchResult(query); - Arrays.stream(initial.getElements()).flatMap(element -> Arrays.stream(initial.getMatches(element))).filter(FileMatch.class::isInstance).forEach(this.filteredFileSearchResult::addMatch); - delegate.inputChanged(viewer, oldInput, this.filteredFileSearchResult); + final var filteredFileSearchResult = this.filteredFileSearchResult = new FileSearchResult(query); + Arrays.stream(initial.getElements()) // + .flatMap(element -> Arrays.stream(initial.getMatches(element))) // + .filter(FileMatch.class::isInstance) // + .forEach(filteredFileSearchResult::addMatch); + delegate.inputChanged(viewer, oldInput, filteredFileSearchResult); } if (newInput instanceof LSSearchResult searchResult) { this.searchResult = searchResult; @@ -44,7 +48,7 @@ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override - public Object[] getElements(Object inputElement) { + public Object[] getElements(@Nullable Object inputElement) { List res = new ArrayList<>(); res.addAll(Arrays.asList(delegate.getElements(inputElement == this.searchResult ? this.filteredFileSearchResult : inputElement))); if (inputElement instanceof AbstractTextSearchResult searchResult) { @@ -62,13 +66,13 @@ public Object[] getChildren(Object parentElement) { } @Override - public Object getParent(Object element) { + public @Nullable Object getParent(Object element) { return delegate.getParent(element); } @Override public boolean hasChildren(Object element) { - return delegate.hasChildren(element) || Arrays.asList(searchResult.getElements()).contains(element); + return delegate.hasChildren(element) || (searchResult != null && Arrays.asList(searchResult.getElements()).contains(element)); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchLabelProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchLabelProvider.java index 8f448a9d5..7e6ef72f2 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchLabelProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/FileAndURIMatchLabelProvider.java @@ -12,6 +12,7 @@ import java.net.URI; import java.net.URISyntaxException; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.StyledString; @@ -53,7 +54,7 @@ public void removeListener(ILabelProviderListener listener) { } @Override - public StyledString getStyledText(Object element) { + public @Nullable StyledString getStyledText(@Nullable Object element) { if (canDelegate(element)) { return resourceMatchDelegate.getStyledText(element); } @@ -84,7 +85,7 @@ public StyledString getStyledText(Object element) { } @Override - public Image getImage(Object element) { + public @Nullable Image getImage(@Nullable Object element) { if (canDelegate(element)) { return resourceMatchDelegate.getImage(element); } @@ -99,7 +100,7 @@ public Image getImage(Object element) { return null; } - private boolean canDelegate(Object element) { + private boolean canDelegate(@Nullable Object element) { return !(element instanceof URI || element instanceof URIMatch); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSFindReferences.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSFindReferences.java index bc49e668e..6f1d3d379 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSFindReferences.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSFindReferences.java @@ -15,6 +15,7 @@ import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.IHandler; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; @@ -49,7 +50,7 @@ protected void execute(ExecutionEvent event, ITextEditor textEditor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getReferencesProvider, this::hasSelection); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchQuery.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchQuery.java index ba936aa7b..725d054d2 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchQuery.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchQuery.java @@ -14,7 +14,6 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.references; -import java.net.URISyntaxException; import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -29,7 +28,7 @@ import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -54,10 +53,10 @@ */ public class LSSearchQuery extends FileSearchQuery { - private final @NonNull IDocument document; + private final IDocument document; private final int offset; - private LSSearchResult result; + private @Nullable LSSearchResult result; /** * LSP search query to "Find references" from the given offset of the given @@ -66,14 +65,14 @@ public class LSSearchQuery extends FileSearchQuery { * @param offset * @param document */ - public LSSearchQuery(int offset, @NonNull IDocument document) { + public LSSearchQuery(int offset, IDocument document) { super("", false, false, true, true, null); //$NON-NLS-1$ this.document = document; this.offset = offset; } @Override - public IStatus run(IProgressMonitor monitor) throws OperationCanceledException { + public IStatus run(@Nullable IProgressMonitor monitor) throws OperationCanceledException { getSearchResult().removeAll(); try { @@ -83,11 +82,12 @@ public IStatus run(IProgressMonitor monitor) throws OperationCanceledException { params.setTextDocument(LSPEclipseUtils.toTextDocumentIdentifier(document)); params.setPosition(LSPEclipseUtils.toPosition(offset, document)); - @NonNull List<@NonNull CompletableFuture>> requests = LanguageServers.forDocument(document).withCapability(ServerCapabilities::getReferencesProvider) + List>> requests = LanguageServers.forDocument(document).withCapability(ServerCapabilities::getReferencesProvider) .computeAll(languageServer -> languageServer.getTextDocumentService().references(params)); CompletableFuture[] populateUIFutures = requests.stream().map(request -> request.thenAcceptAsync(locations -> { - if (locations != null) { + final var result = this.result; + if (locations != null && result != null) { // Convert each LSP Location to a Match search. locations.stream() // .filter(Objects::nonNull) // @@ -111,7 +111,7 @@ public IStatus run(IProgressMonitor monitor) throws OperationCanceledException { * the LSP location to convert. * @return the converted Eclipse search {@link Match}. */ - private static Match toMatch(@NonNull Location location) { + private static @Nullable Match toMatch(Location location) { IResource resource = LSPEclipseUtils.findResourceFor(location.getUri()); if (resource != null) { IDocument document = LSPEclipseUtils.getExistingDocument(resource); @@ -149,7 +149,7 @@ private static Match toMatch(@NonNull Location location) { } try { return URIMatch.create(location); - } catch (BadLocationException | URISyntaxException ex) { + } catch (Exception ex) { LanguageServerPlugin.logError(ex); return null; } @@ -157,8 +157,9 @@ private static Match toMatch(@NonNull Location location) { @Override public LSSearchResult getSearchResult() { + var result = this.result; if (result == null) { - result = new LSSearchResult(this); + result = this.result = new LSSearchResult(this); } return result; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResult.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResult.java index 6165b33a1..f5a1902d4 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResult.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResult.java @@ -18,6 +18,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.eclipse.core.resources.IFile; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.search.internal.ui.text.FileSearchResult; import org.eclipse.search.ui.ISearchResult; import org.eclipse.search.ui.text.AbstractTextSearchResult; @@ -42,7 +43,7 @@ public LSSearchResult(LSSearchQuery query) { private final Set nonFileElements = ConcurrentHashMap.newKeySet(); @Override - public IFile getFile(Object element) { + public @Nullable IFile getFile(@Nullable Object element) { return element instanceof IFile file ? file : null; } @@ -76,12 +77,12 @@ public LSSearchQuery getQuery() { } @Override - public IFileMatchAdapter getFileMatchAdapter() { + public @Nullable IFileMatchAdapter getFileMatchAdapter() { return this; } @Override - public IEditorMatchAdapter getEditorMatchAdapter() { + public @Nullable IEditorMatchAdapter getEditorMatchAdapter() { return this; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResultPage.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResultPage.java index 60fc292a9..e218d796e 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResultPage.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/LSSearchResultPage.java @@ -12,8 +12,8 @@ import java.util.Set; import org.eclipse.core.resources.IContainer; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; @@ -32,20 +32,18 @@ */ public class LSSearchResultPage extends FileSearchPage { - private ITreeContentProvider contentProvider; - @Override public void configureTreeViewer(TreeViewer viewer) { super.configureTreeViewer(viewer); FileTreeContentProvider fileMatchContentProvider = (FileTreeContentProvider)viewer.getContentProvider(); - this.contentProvider = new FileAndURIMatchContentProvider(fileMatchContentProvider); - viewer.setContentProvider(this.contentProvider); + final var contentProvider = new FileAndURIMatchContentProvider(fileMatchContentProvider); + viewer.setContentProvider(contentProvider); DecoratingFileSearchLabelProvider fileMatchDecoratingLabelProvider = (DecoratingFileSearchLabelProvider)viewer.getLabelProvider(); FileAndURIMatchBaseLabelProvider baseLabelProvider = new FileAndURIMatchBaseLabelProvider(fileMatchDecoratingLabelProvider.getStyledStringProvider()); viewer.setLabelProvider(new FileAndURIMatchLabelProvider(baseLabelProvider, fileMatchDecoratingLabelProvider)); viewer.setComparator(new ViewerComparator() { @Override - public int category(Object element) { + public int category(@Nullable Object element) { if (element instanceof IContainer) { return 1; } else if (element instanceof URI uri) { @@ -59,7 +57,7 @@ public int category(Object element) { } @Override - public int compare(Viewer viewer, Object e1, Object e2) { + public int compare(@Nullable Viewer viewer, @Nullable Object e1, @Nullable Object e2) { int cat1 = category(e1); int cat2 = category(e2); if (cat1 != cat2) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/package-info.java new file mode 100644 index 000000000..746ec2851 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/references/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.references; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameHandler.java index f8e17d52e..f7ce8942b 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameHandler.java @@ -16,6 +16,7 @@ package org.eclipse.lsp4e.operations.rename; import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelectionProvider; @@ -66,7 +67,7 @@ protected void execute(ExecutionEvent event, ITextEditor textEditor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getRenameProvider, this::hasSelection); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameProcessor.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameProcessor.java index 1e9bef792..478619448 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameProcessor.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameProcessor.java @@ -25,7 +25,6 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -56,29 +55,28 @@ /** * LTK {@link RefactoringProcessor} implementation to refactoring LSP symbols. - * */ public class LSPRenameProcessor extends RefactoringProcessor { private static final String ID = "org.eclipse.lsp4e.operations.rename"; //$NON-NLS-1$ - private final @NonNull IDocument document; + private final IDocument document; private final int offset; - private LanguageServerWrapper refactoringServer; + private @Nullable LanguageServerWrapper refactoringServer; - private String newName; + private @Nullable String newName; - private WorkspaceEdit rename; - private Either3 prepareRenameResult; + private @Nullable WorkspaceEdit rename; + private @Nullable Either3 prepareRenameResult; - public LSPRenameProcessor(@NonNull IDocument document, int offset) { + public LSPRenameProcessor(IDocument document, int offset) { this.document = document; this.offset = offset; } @Override - public Object[] getElements() { + public Object @Nullable [] getElements() { return null; } @@ -127,7 +125,9 @@ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) }); } } catch (TimeoutException e) { - LanguageServerPlugin.logWarning("Could not prepare rename due to timeout after 1 seconds in `textDocument/prepareRename`. 'newName' will be used", e); //$NON-NLS-1$ + LanguageServerPlugin.logWarning( + "Could not prepare rename due to timeout after 1 seconds in `textDocument/prepareRename`. 'newName' will be used", //$NON-NLS-1$ + e); } catch (Exception e) { status.addFatalError(getErrorMessage(e)); } @@ -135,7 +135,8 @@ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) } public String getPlaceholder() { - @Nullable String placeholder = null; + @Nullable + String placeholder = null; if (prepareRenameResult != null) { placeholder = prepareRenameResult.map(range -> { try { @@ -146,13 +147,12 @@ public String getPlaceholder() { LanguageServerPlugin.logError(e); return null; } - }, PrepareRenameResult::getPlaceholder, - options -> null); + }, PrepareRenameResult::getPlaceholder, options -> null); } - return placeholder != null && !placeholder.isBlank() ? placeholder :"newName"; //$NON-NLS-1$ + return placeholder != null && !placeholder.isBlank() ? placeholder : "newName"; //$NON-NLS-1$ } - public static boolean isPrepareRenameProvider(ServerCapabilities serverCapabilities) { + public static boolean isPrepareRenameProvider(@Nullable ServerCapabilities serverCapabilities) { if (serverCapabilities == null) { return false; } @@ -162,7 +162,7 @@ public static boolean isPrepareRenameProvider(ServerCapabilities serverCapabilit } if (renameProvider.isRight()) { - return renameProvider.getRight() != null && renameProvider.getRight().getPrepareProvider(); + return renameProvider.getRight().getPrepareProvider(); } return false; } @@ -171,6 +171,10 @@ public static boolean isPrepareRenameProvider(ServerCapabilities serverCapabilit public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException, OperationCanceledException { final var status = new RefactoringStatus(); + final var newName = this.newName; + if (newName == null) { + return status; + } try { final var params = new RenameParams(); params.setPosition(LSPEclipseUtils.toPosition(offset, document)); @@ -178,19 +182,23 @@ public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditio identifier.setUri(LSPEclipseUtils.toUri(document).toString()); params.setTextDocument(identifier); params.setNewName(newName); - if (params.getNewName() != null && refactoringServer != null) { - // TODO: how to manage ltk with CompletableFuture? Is 1000 ms is enough? - if (refactoringServer != null) { - rename = refactoringServer.execute(ls -> ls.getTextDocumentService().rename(params)).get(1000, TimeUnit.MILLISECONDS); - } else { - // Prepare timed out so we don't have a preferred server, so just try all the servers again - rename = LanguageServers.forDocument(document).withCapability(ServerCapabilities::getRenameProvider) - .computeFirst(ls -> ls.getTextDocumentService().rename(params)).get(1000, TimeUnit.MILLISECONDS).orElse(null); - } - if (!status.hasError() && (rename == null - || (rename.getChanges().isEmpty() && rename.getDocumentChanges().isEmpty()))) { - status.addWarning(Messages.rename_empty_message); - } + + // TODO: how to manage ltk with CompletableFuture? Is 1000 ms is enough? + final var refactoringServer = this.refactoringServer; + final WorkspaceEdit rename; + if (refactoringServer != null) { + rename = this.rename = refactoringServer.execute(ls -> ls.getTextDocumentService().rename(params)) + .get(1000, TimeUnit.MILLISECONDS); + } else { + // Prepare timed out so we don't have a preferred server, so just try all the servers again + rename = this.rename = LanguageServers.forDocument(document) + .withCapability(ServerCapabilities::getRenameProvider) + .computeFirst(ls -> ls.getTextDocumentService().rename(params)).get(1000, TimeUnit.MILLISECONDS) + .orElse(null); + } + if (!status.hasError() + && (rename == null || (rename.getChanges().isEmpty() && rename.getDocumentChanges().isEmpty()))) { + status.addWarning(Messages.rename_empty_message); } } catch (Exception e) { status.addFatalError(getErrorMessage(e)); @@ -201,10 +209,10 @@ public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditio private String getErrorMessage(Throwable e) { if (e.getCause() instanceof ResponseErrorException responseErrorException) { ResponseError responseError = responseErrorException.getResponseError(); - return responseError.getMessage() - + ((responseError.getData() instanceof String data) ? (": " + data) : ""); //$NON-NLS-1$ //$NON-NLS-2$ + return responseError.getMessage() + ((responseError.getData() instanceof String data) ? (": " + data) : ""); //$NON-NLS-1$ //$NON-NLS-2$ } else { - return e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName(); + final var msg = e.getMessage(); + return msg != null ? msg : e.getClass().getSimpleName(); } } @@ -218,8 +226,8 @@ public Change createChange(IProgressMonitor pm) throws CoreException, OperationC } @Override - public RefactoringParticipant[] loadParticipants(RefactoringStatus status, SharableParticipants sharedParticipants) - throws CoreException { + public RefactoringParticipant @Nullable [] loadParticipants(RefactoringStatus status, + SharableParticipants sharedParticipants) throws CoreException { return null; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameRefactoringWizard.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameRefactoringWizard.java index c7646a505..4e001a095 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameRefactoringWizard.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/LSPRenameRefactoringWizard.java @@ -11,6 +11,8 @@ */ package org.eclipse.lsp4e.operations.rename; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.lateNonNull; + import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.lsp4e.ui.Messages; import org.eclipse.ltk.core.refactoring.Refactoring; @@ -37,18 +39,19 @@ public LSPRenameRefactoringWizard(Refactoring refactoring) { @Override protected void addUserInputPages() { - @SuppressWarnings("null") LSPRenameProcessor processor = this.getRefactoring().getAdapter(LSPRenameProcessor.class); - this.addPage(new RenameInputWizardPage(processor)); + if(processor != null) { + this.addPage(new RenameInputWizardPage(processor)); + } } /** * Rename input wizard page. * */ - class RenameInputWizardPage extends UserInputWizardPage { + static final class RenameInputWizardPage extends UserInputWizardPage { - private Text nameText; + private Text nameText = lateNonNull(); private final LSPRenameProcessor processor; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/package-info.java new file mode 100644 index 000000000..59f70b1e0 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/rename/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.rename; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/LSPSelectionRangeAbstractHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/LSPSelectionRangeAbstractHandler.java index a30cf98d8..df098975c 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/LSPSelectionRangeAbstractHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/LSPSelectionRangeAbstractHandler.java @@ -18,6 +18,7 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; @@ -58,12 +59,9 @@ public enum Direction { private static final String KEY = SelectionRangeHandler.class.getName(); - private SelectionRange root; - - private SelectionRange previous; - + private @Nullable SelectionRange root; + private @Nullable SelectionRange previous; private final StyledText styledText; - private boolean updating; public void setRoot(SelectionRange root) { @@ -90,10 +88,11 @@ public SelectionRangeHandler(StyledText styledText) { }); } - public SelectionRange getSelectionRange(Direction direction) { + public @Nullable SelectionRange getSelectionRange(Direction direction) { + var previous = this.previous; if (direction == Direction.UP) { if (previous != null) { - previous = previous.getParent(); + previous = this.previous = previous.getParent(); return previous; } } else { @@ -102,7 +101,7 @@ public SelectionRange getSelectionRange(Direction direction) { while (selectionRange != null) { SelectionRange parent = selectionRange.getParent(); if (previous.equals(parent)) { - previous = selectionRange; + previous = this.previous = selectionRange; return previous; } selectionRange = parent; @@ -203,7 +202,7 @@ protected void execute(ExecutionEvent event, ITextEditor textEditor) { * @return the selection range hierarchy of the given document at the given * offset. */ - private CompletableFuture>> collectSelectionRanges(IDocument document, int offset) { + private CompletableFuture>> collectSelectionRanges(@Nullable IDocument document, int offset) { if (document == null) { return CompletableFuture.completedFuture(null); } @@ -222,7 +221,7 @@ private CompletableFuture>> collectSelectionRanges } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getSelectionRangeProvider, x -> true); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/package-info.java new file mode 100644 index 000000000..62f881bc3 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/selectionRange/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.selectionRange; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticHighlightReconcilerStrategy.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticHighlightReconcilerStrategy.java index 628b034ac..78714a818 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticHighlightReconcilerStrategy.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticHighlightReconcilerStrategy.java @@ -8,6 +8,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.semanticTokens; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull; + import java.net.URI; import java.util.List; import java.util.Optional; @@ -17,7 +19,6 @@ import java.util.function.Function; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; @@ -84,15 +85,13 @@ public class SemanticHighlightReconcilerStrategy private final boolean disabled; - private ITextViewer viewer; - - private IDocument document; + private @Nullable ITextViewer viewer; - private StyleRangeHolder styleRangeHolder; + private @Nullable IDocument document; - private SemanticTokensDataStreamProcessor semanticTokensDataStreamProcessor; + private @Nullable StyleRangeHolder styleRangeHolder; - private boolean isInstalled; + private @Nullable SemanticTokensDataStreamProcessor semanticTokensDataStreamProcessor; /** * Written in {@link this.class#applyTextPresentation(TextPresentation)} @@ -107,12 +106,11 @@ public class SemanticHighlightReconcilerStrategy private volatile long timestamp = 0; - private CompletableFuture> semanticTokensFullFuture; + private @Nullable CompletableFuture> semanticTokensFullFuture; public SemanticHighlightReconcilerStrategy() { IPreferenceStore store = LanguageServerPlugin.getDefault().getPreferenceStore(); disabled = store.getBoolean("semanticHighlightReconciler.disabled"); //$NON-NLS-1$ - isInstalled = false; } /** @@ -125,19 +123,18 @@ public SemanticHighlightReconcilerStrategy() { */ @Override public void install(final ITextViewer textViewer) { - if (disabled || isInstalled) { + if (disabled || viewer == null) { return; } - viewer = textViewer; - styleRangeHolder = new StyleRangeHolder(); semanticTokensDataStreamProcessor = new SemanticTokensDataStreamProcessor(new TokenTypeMapper(textViewer), offsetMapper()); - if (viewer instanceof final TextViewer textViewerImpl) { + if (textViewer instanceof final TextViewer textViewerImpl) { textViewerImpl.addTextPresentationListener(this); } - viewer.addTextListener(styleRangeHolder); - isInstalled = true; + styleRangeHolder = new StyleRangeHolder(); + textViewer.addTextListener(styleRangeHolder); + viewer = textViewer; } /** @@ -146,31 +143,33 @@ public void install(final ITextViewer textViewer) { */ @Override public void uninstall() { - if (disabled || !isInstalled) { + final var viewer = this.viewer; + if (disabled || viewer == null) { return; } - isInstalled = false; // Indicate that we're not installed or in the phase of deinstalling + this.viewer = null; // Indicate that we're not installed or in the phase of deinstalling cancelSemanticTokensFull(); semanticTokensDataStreamProcessor = null; if (viewer instanceof final TextViewer textViewerImpl) { textViewerImpl.removeTextPresentationListener(this); } - viewer.removeTextListener(styleRangeHolder); - viewer = null; - styleRangeHolder = null; + if (styleRangeHolder != null) { + viewer.removeTextListener(styleRangeHolder); + styleRangeHolder = null; + } } - private @NonNull Function offsetMapper() { + private Function offsetMapper() { return p -> { try { - return LSPEclipseUtils.toOffset(p, document); + return LSPEclipseUtils.toOffset(p, castNonNull(document)); } catch (BadLocationException e) { throw new RuntimeException(e); } }; } - private SemanticTokensParams getSemanticTokensParams() { + private @Nullable SemanticTokensParams getSemanticTokensParams() { URI uri = LSPEclipseUtils.toUri(document); if (uri != null) { final var semanticTokensParams = new SemanticTokensParams(); @@ -180,16 +179,18 @@ private SemanticTokensParams getSemanticTokensParams() { return null; } - private void saveStyle(final Pair pair) { + private void saveStyle(final Pair<@Nullable SemanticTokens, @Nullable SemanticTokensLegend> pair) { final SemanticTokens semanticTokens = pair.first(); final SemanticTokensLegend semanticTokensLegend = pair.second(); // Skip any processing if not installed or at least one of the pair values is null - if (!isInstalled || semanticTokens == null || semanticTokensLegend == null) { + if (viewer == null || semanticTokens == null || semanticTokensLegend == null) { return; } List dataStream = semanticTokens.getData(); - if (!dataStream.isEmpty()) { + final var semanticTokensDataStreamProcessor = this.semanticTokensDataStreamProcessor; + final var styleRangeHolder = this.styleRangeHolder; + if (!dataStream.isEmpty() && semanticTokensDataStreamProcessor != null && styleRangeHolder != null) { List styleRanges = semanticTokensDataStreamProcessor.getStyleRanges(dataStream, semanticTokensLegend); styleRangeHolder.saveStyles(styleRanges); @@ -197,11 +198,11 @@ private void saveStyle(final Pair pair) { } @Override - public void setProgressMonitor(final IProgressMonitor monitor) { + public void setProgressMonitor(final @Nullable IProgressMonitor monitor) { } @Override - public void setDocument(final IDocument document) { + public void setDocument(final @Nullable IDocument document) { this.document = document; } @@ -235,16 +236,17 @@ private boolean outdatedTextPresentation(final long documentTimestamp) { } private void invalidateTextPresentation(final Long documentTimestamp) { - if (!isInstalled) { // Skip any processing + final var viewer = this.viewer; + if (viewer == null) { // Skip any processing return; } StyledText textWidget = viewer.getTextWidget(); textWidget.getDisplay().asyncExec(() -> { if (!textWidget.isDisposed() && outdatedTextPresentation(documentTimestamp)) { - ITextViewer theViewer = viewer; + ITextViewer theViewer = this.viewer; if (theViewer != null) { theViewer.invalidateTextPresentation(); - } + } } }); } @@ -256,25 +258,25 @@ private void cancelSemanticTokensFull() { } private void fullReconcile() { - if (disabled || !isInstalled) { // Skip any processing + final var viewer = this.viewer; + if (disabled || viewer == null) { // Skip any processing return; } - IDocument theDocument = document; + final var document = this.document; cancelSemanticTokensFull(); - if (theDocument != null) { - long modificationStamp = DocumentUtil.getDocumentModificationStamp(theDocument); - LanguageServerDocumentExecutor executor = LanguageServers.forDocument(theDocument) + if (document != null) { + long modificationStamp = DocumentUtil.getDocumentModificationStamp(document); + LanguageServerDocumentExecutor executor = LanguageServers.forDocument(document) .withFilter(this::hasSemanticTokensFull); try { - semanticTokensFullFuture = executor// - .computeFirst((w, ls) -> ls.getTextDocumentService().semanticTokensFull(getSemanticTokensParams())// + final var semanticTokensFullFuture = executor // + .computeFirst((w, ls) -> ls.getTextDocumentService().semanticTokensFull(getSemanticTokensParams()) // .thenApply(semanticTokens -> new VersionedSemanticTokens(modificationStamp, - Pair.of(semanticTokens, getSemanticTokensLegend(w)), theDocument))); - + Pair.of(semanticTokens, getSemanticTokensLegend(w)), document))); + this.semanticTokensFullFuture = semanticTokensFullFuture; semanticTokensFullFuture.get() // background thread with cancellation support, no timeout needed - .ifPresent(versionedSemanticTokens -> { - versionedSemanticTokens.apply(this::saveStyle, this::invalidateTextPresentation); - }); + .ifPresent(versionedSemanticTokens -> + versionedSemanticTokens.apply(this::saveStyle, this::invalidateTextPresentation)); } catch (InterruptedException e) { LanguageServerPlugin.logError(e); Thread.currentThread().interrupt(); @@ -317,7 +319,7 @@ private void fullReconcileOnce() { public void applyTextPresentation(final TextPresentation textPresentation) { documentTimestampAtLastAppliedTextPresentation = DocumentUtil.getDocumentModificationStamp(document); IRegion extent = textPresentation.getExtent(); - if (extent != null) { + if (extent != null && styleRangeHolder != null) { textPresentation.replaceStyleRanges(styleRangeHolder.overlappingRanges(extent)); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticTokensDataStreamProcessor.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticTokensDataStreamProcessor.java index 0647a1f77..13490eb94 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticTokensDataStreamProcessor.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/SemanticTokensDataStreamProcessor.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.function.Function; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.TextAttribute; import org.eclipse.jface.text.rules.IToken; @@ -33,7 +32,7 @@ public class SemanticTokensDataStreamProcessor { private final Function offsetMapper; - private final Function tokenTypeMapper; + private final Function tokenTypeMapper; /** * Creates a new instance of {@link SemanticTokensDataStreamProcessor}. @@ -41,8 +40,8 @@ public class SemanticTokensDataStreamProcessor { * @param tokenTypeMapper * @param offsetMapper */ - public SemanticTokensDataStreamProcessor(@NonNull final Function tokenTypeMapper, - @NonNull final Function offsetMapper) { + public SemanticTokensDataStreamProcessor(final Function tokenTypeMapper, + final Function offsetMapper) { this.tokenTypeMapper = tokenTypeMapper; this.offsetMapper = offsetMapper; } @@ -52,10 +51,9 @@ public SemanticTokensDataStreamProcessor(@NonNull final Function * * @param dataStream * @param semanticTokensLegend - * @return */ - public @NonNull List getStyleRanges(@NonNull final List dataStream, - @NonNull final SemanticTokensLegend semanticTokensLegend) { + public List getStyleRanges(final List dataStream, + final SemanticTokensLegend semanticTokensLegend) { final var styleRanges = new ArrayList(dataStream.size() / 5); int idx = 0; @@ -104,7 +102,7 @@ public SemanticTokensDataStreamProcessor(@NonNull final Function return styleRanges; } - private String tokenType(final Integer data, final List legend) { + private @Nullable String tokenType(final Integer data, final List legend) { try { return legend.get(data); } catch (IndexOutOfBoundsException e) { @@ -129,7 +127,7 @@ private List tokenModifiers(final Integer data, final List legen return tokenModifiers; } - private TextAttribute textAttribute(final String tokenType) { + private @Nullable TextAttribute textAttribute(final @Nullable String tokenType) { if (tokenType != null) { IToken token = tokenTypeMapper.apply(tokenType); if (token != null) { @@ -152,7 +150,7 @@ private TextAttribute textAttribute(final String tokenType) { * @param attr * the attribute describing the style of the range to be styled */ - private @Nullable StyleRange getStyleRange(final int offset, final int length, final TextAttribute attr) { + private @Nullable StyleRange getStyleRange(final int offset, final int length, final @Nullable TextAttribute attr) { if (attr != null) { final int style = attr.getStyle(); final int fontStyle = style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/StyleRangeHolder.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/StyleRangeHolder.java index ee8fe745f..9877d7795 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/StyleRangeHolder.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/StyleRangeHolder.java @@ -13,7 +13,6 @@ import java.util.Comparator; import java.util.List; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextListener; import org.eclipse.jface.text.Region; @@ -43,7 +42,7 @@ public StyleRangeHolder() { * * @param styleRanges */ - public void saveStyles(@NonNull final List styleRanges) { + public void saveStyles(final List styleRanges) { synchronized (previousRanges) { previousRanges.clear(); previousRanges.addAll(styleRanges); @@ -55,9 +54,8 @@ public void saveStyles(@NonNull final List styleRanges) { * return a copy of the saved styles that overlap the given region. * * @param region - * @return */ - public StyleRange[] overlappingRanges(@NonNull final IRegion region) { + public StyleRange[] overlappingRanges(final IRegion region) { synchronized (previousRanges) { // we need to create new styles because the text presentation might change a // style when applied to the presentation diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/TokenTypeMapper.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/TokenTypeMapper.java index 9ba6e714f..53baa3e58 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/TokenTypeMapper.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/TokenTypeMapper.java @@ -11,7 +11,7 @@ import java.util.function.Function; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.rules.IToken; import org.eclipse.tm4e.ui.text.TMPresentationReconciler; @@ -20,15 +20,15 @@ /** * A Class that maps TokenTypes to {@link IToken}. */ -public class TokenTypeMapper implements Function { - private @NonNull final ITextViewer viewer; +public class TokenTypeMapper implements Function { + private final ITextViewer viewer; - public TokenTypeMapper(@NonNull final ITextViewer viewer) { + public TokenTypeMapper(final ITextViewer viewer) { this.viewer = viewer; } @Override - public IToken apply(final String tokenType) { + public @Nullable IToken apply(final @Nullable String tokenType) { if (tokenType == null) { return null; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/VersionedSemanticTokens.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/VersionedSemanticTokens.java index 85508f930..18f192586 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/VersionedSemanticTokens.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/VersionedSemanticTokens.java @@ -14,6 +14,7 @@ import java.util.function.Consumer; import java.util.function.LongConsumer; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.lsp4e.Versioned; import org.eclipse.lsp4e.internal.DocumentUtil; @@ -23,11 +24,11 @@ /** * Specialization of Versioned for semanticTokens - * */ -public class VersionedSemanticTokens extends Versioned>{ +public class VersionedSemanticTokens extends Versioned>{ - public VersionedSemanticTokens(long version, Pair data, IDocument document) { + public VersionedSemanticTokens(long version, Pair<@Nullable SemanticTokens, @Nullable SemanticTokensLegend> data, + IDocument document) { super(document, version, data); } @@ -36,7 +37,7 @@ public VersionedSemanticTokens(long version, Pair> first, LongConsumer second) { + public void apply(Consumer> first, LongConsumer second) { if (sourceDocumentVersion == DocumentUtil.getDocumentModificationStamp(document)) { first.accept(data); second.accept(sourceDocumentVersion); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/package-info.java new file mode 100644 index 000000000..ad6803b93 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/semanticTokens/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.semanticTokens; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileDialog.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileDialog.java index 89c49f221..34818c2e2 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileDialog.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileDialog.java @@ -12,7 +12,7 @@ package org.eclipse.lsp4e.operations.symbols; import org.eclipse.core.resources.IFile; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -55,10 +55,10 @@ public class LSPSymbolInFileDialog extends PopupDialog { private final OutlineViewerInput outlineViewerInput; private final ITextEditor textEditor; - private TreeViewer viewer; + private @Nullable TreeViewer viewer; - public LSPSymbolInFileDialog(@NonNull Shell parentShell, @NonNull ITextEditor textEditor, - @NonNull IDocument document, @NonNull LanguageServerWrapper wrapper) { + public LSPSymbolInFileDialog(Shell parentShell, ITextEditor textEditor, + IDocument document, LanguageServerWrapper wrapper) { super(parentShell, PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE, true, true, true, false, false, null, null); outlineViewerInput = new OutlineViewerInput(document, wrapper, textEditor); this.textEditor = textEditor; @@ -71,7 +71,7 @@ protected Control createDialogArea(Composite parent) { getShell().setText(NLS.bind(Messages.symbolsInFile, documentFile == null ? null : documentFile.getName())); final var filteredTree = new FilteredTree(parent, SWT.BORDER, new PatternFilter(), true, false); - viewer = filteredTree.getViewer(); + final TreeViewer viewer = this.viewer = filteredTree.getViewer(); viewer.setData(LSSymbolsContentProvider.VIEWER_PROPERTY_IS_QUICK_OUTLINE, Boolean.TRUE); final var contentService = new NavigatorContentService(CNFOutlinePage.ID, viewer); @@ -130,14 +130,14 @@ public void mouseUp(MouseEvent e) { } }); - this.getShell().addDisposeListener(event -> viewer = null); + getShell().addDisposeListener(event -> this.viewer = null); viewer.setInput(outlineViewerInput); return filteredTree; } private void gotoSelectedElement() { - Object selectedElement= getSelectedElement(); + Object selectedElement = getSelectedElement(); if (selectedElement != null) { close(); @@ -163,7 +163,7 @@ private void gotoSelectedElement() { } } - private Object getSelectedElement() { + private @Nullable Object getSelectedElement() { TreeViewer treeViewer = this.viewer; if (treeViewer == null) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileHandler.java index ef0bc39e4..0da276aee 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInFileHandler.java @@ -15,6 +15,7 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServers; @@ -51,7 +52,7 @@ protected void execute(ExecutionEvent event, ITextEditor textEditor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getDocumentSymbolProvider, x -> true); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceDialog.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceDialog.java index 48260aea5..8e7c8edd8 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceDialog.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceDialog.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -28,7 +29,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -57,7 +58,7 @@ public class LSPSymbolInWorkspaceDialog extends FilteredItemsSelectionDialog { private static final class InternalSymbolsLabelProvider extends SymbolsLabelProvider { - private String pattern; + private @Nullable String pattern; private final BoldStylerProvider stylerProvider; public InternalSymbolsLabelProvider(BoldStylerProvider stylerProvider) { @@ -67,17 +68,21 @@ public InternalSymbolsLabelProvider(BoldStylerProvider stylerProvider) { } @Override - public StyledString getStyledText(Object element) { + public StyledString getStyledText(@Nullable Object element) { StyledString styledString = super.getStyledText(element); - int index = styledString.getString().toLowerCase().indexOf(pattern); - if (index != -1) { - styledString.setStyle(index, pattern.length(), stylerProvider.getBoldStyler()); + final var pattern = this.pattern; + if (pattern != null) { + int index = styledString.getString().toLowerCase().indexOf(pattern); + if (index != -1) { + styledString.setStyle(index, pattern.length(), stylerProvider.getBoldStyler()); + } } return styledString; } @Override - protected int getMaxSeverity(@NonNull IResource resource, @NonNull IDocument doc, @NonNull Range range) throws CoreException, BadLocationException { + protected int getMaxSeverity(IResource resource, IDocument doc, Range range) + throws CoreException, BadLocationException { int maxSeverity = -1; for (IMarker marker : resource.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO)) { int offset = marker.getAttribute(IMarker.CHAR_START, -1); @@ -88,7 +93,7 @@ protected int getMaxSeverity(@NonNull IResource resource, @NonNull IDocument doc return maxSeverity; } - public void setPattern(String pattern) { + public void setPattern(@Nullable String pattern) { this.pattern = pattern; } } @@ -96,17 +101,17 @@ public void setPattern(String pattern) { private final class InternalItemsFilter extends ItemsFilter { @Override - public boolean matchItem(Object item) { + public boolean matchItem(@Nullable Object item) { return true; } @Override - public boolean isConsistentItem(Object item) { + public boolean isConsistentItem(@Nullable Object item) { return true; } @Override - public boolean isSubFilter(ItemsFilter filter) { + public boolean isSubFilter(@Nullable ItemsFilter filter) { return false; } } @@ -115,7 +120,7 @@ public boolean isSubFilter(ItemsFilter filter) { private final IProject project; - private List, List>>> request; + private @Nullable List, List>>> request; public LSPSymbolInWorkspaceDialog(Shell shell, IProject project, BoldStylerProvider stylerProvider) { super(shell); @@ -143,36 +148,36 @@ protected void fillContentProvider(AbstractContentProvider contentProvider, Item return; } final var params = new WorkspaceSymbolParams(itemsFilter.getPattern()); - request = LanguageServers.forProject(project).withCapability(ServerCapabilities::getWorkspaceSymbolProvider) - .computeAll((w, ls) -> ls.getWorkspaceService().symbol(params)); - request.stream().map(s -> s.thenApply(LSPSymbolInWorkspaceDialog::eitherToWorkspaceSymbols)) - .forEach(cf -> { - if (monitor.isCanceled()) { - return; - } - try { - final List items = cf.get(1, TimeUnit.SECONDS); - if(items != null) { - for (Object item : items) { - if (item != null) { - contentProvider.add(item, itemsFilter); - } + request = LanguageServers.forProject(project) // + .withCapability(ServerCapabilities::getWorkspaceSymbolProvider) // + .computeAll((w, ls) -> ls.getWorkspaceService().symbol(params)); + request.stream().map(( + CompletableFuture<@Nullable Either, List<@Nullable ? extends WorkspaceSymbol>>> f) -> f + .thenApply(LSPSymbolInWorkspaceDialog::eitherToWorkspaceSymbols)) + .forEach(cf -> { + if (monitor.isCanceled()) { + return; + } + try { + for (Object item : cf.get(1, TimeUnit.SECONDS)) { + contentProvider.add(item, itemsFilter); } + } catch (ExecutionException e) { + LanguageServerPlugin.logError(e); + } catch (InterruptedException e) { + LanguageServerPlugin.logError(e); + Thread.currentThread().interrupt(); + } catch (TimeoutException e) { + LanguageServerPlugin.logWarning( + "Could not get workspace symbols due to timeout after 1 seconds in `workspace/symbol`", //$NON-NLS-1$ + e); } - } catch (ExecutionException e) { - LanguageServerPlugin.logError(e); - } catch (InterruptedException e) { - LanguageServerPlugin.logError(e); - Thread.currentThread().interrupt(); - } catch (TimeoutException e) { - LanguageServerPlugin.logWarning("Could not get workspace symbols due to timeout after 1 seconds in `workspace/symbol`", e); //$NON-NLS-1$ - } - }); + }); } @Override public String getElementName(Object item) { - return ((WorkspaceSymbol)item).getName(); + return ((WorkspaceSymbol) item).getName(); } @Override @@ -195,17 +200,20 @@ protected IDialogSettings getDialogSettings() { } @Override - protected Control createExtendedContentArea(Composite parent) { + protected @Nullable Control createExtendedContentArea(Composite parent) { return null; } - private static List toWorkspaceSymbols(List source) { - return source == null ? - List.of() : - source.stream().map(LSPSymbolInWorkspaceDialog::toWorkspaceSymbol).toList(); + private static List toWorkspaceSymbols(@Nullable List source) { + return source == null // + ? List.of() + : source.stream() // + .map(LSPSymbolInWorkspaceDialog::toWorkspaceSymbol) // + .filter(Objects::nonNull) // + .toList(); } - private static WorkspaceSymbol toWorkspaceSymbol(SymbolInformation symbolinformation) { + private static @Nullable WorkspaceSymbol toWorkspaceSymbol(@Nullable SymbolInformation symbolinformation) { if (symbolinformation == null) { return null; } @@ -214,7 +222,8 @@ private static WorkspaceSymbol toWorkspaceSymbol(SymbolInformation symbolinforma res.setLocation(Either.forLeft(symbolinformation.getLocation())); res.setKind(symbolinformation.getKind()); res.setContainerName(symbolinformation.getContainerName()); - List tags = symbolinformation.getTags() != null ? new ArrayList<>(symbolinformation.getTags()) : new ArrayList<>(1); + List tags = symbolinformation.getTags() != null ? new ArrayList<>(symbolinformation.getTags()) + : new ArrayList<>(1); if (symbolinformation.getDeprecated() != null && symbolinformation.getDeprecated().booleanValue()) { tags.add(SymbolTag.Deprecated); } @@ -222,7 +231,10 @@ private static WorkspaceSymbol toWorkspaceSymbol(SymbolInformation symbolinforma return res; } - static List eitherToWorkspaceSymbols(Either, List> source) { - return source.map(LSPSymbolInWorkspaceDialog::toWorkspaceSymbols, Function.identity()); + static List eitherToWorkspaceSymbols( + final @Nullable Either, List<@Nullable ? extends WorkspaceSymbol>> source) { + return source == null // + ? List.of() + : source.map(LSPSymbolInWorkspaceDialog::toWorkspaceSymbols, Function.identity()); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceHandler.java index a36dc9ebb..0c7e66165 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/LSPSymbolInWorkspaceHandler.java @@ -16,6 +16,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.text.contentassist.BoldStylerProvider; import org.eclipse.jface.viewers.IStructuredSelection; @@ -33,7 +34,7 @@ public class LSPSymbolInWorkspaceHandler extends LSPDocumentAbstractHandler { @Override - public Object execute(ExecutionEvent event) throws ExecutionException { + public @Nullable Object execute(ExecutionEvent event) throws ExecutionException { IEditorPart part = HandlerUtil.getActiveEditor(event); IResource resource = null; if (part != null && part.getEditorInput() != null) { @@ -81,7 +82,7 @@ protected void execute(ExecutionEvent event, ITextEditor textEditor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getWorkspaceSymbolProvider, x -> true); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/WorkspaceSymbolsQuickAccessProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/WorkspaceSymbolsQuickAccessProvider.java index 1015af567..88941f932 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/WorkspaceSymbolsQuickAccessProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/WorkspaceSymbolsQuickAccessProvider.java @@ -20,20 +20,22 @@ import java.util.concurrent.TimeoutException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServerPlugin; import org.eclipse.lsp4e.LanguageServerWrapper; import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.WorkspaceSymbol; import org.eclipse.lsp4j.WorkspaceSymbolParams; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.ui.quickaccess.IQuickAccessComputer; import org.eclipse.ui.quickaccess.IQuickAccessComputerExtension; import org.eclipse.ui.quickaccess.QuickAccessElement; public class WorkspaceSymbolsQuickAccessProvider implements IQuickAccessComputer, IQuickAccessComputerExtension { - - private List<@NonNull LanguageServerWrapper> usedLanguageServerWrappers; + private @Nullable List usedLanguageServerWrappers; @Override public QuickAccessElement[] computeElements() { @@ -46,13 +48,15 @@ public void resetState() { @Override public boolean needsRefresh() { - return this.usedLanguageServerWrappers == null - || !this.usedLanguageServerWrappers.equals(LanguageServiceAccessor.getStartedWrappers(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()), true)); + final var usedLanguageServerWrappers = this.usedLanguageServerWrappers; + return usedLanguageServerWrappers == null + || !usedLanguageServerWrappers.equals(LanguageServiceAccessor.getStartedWrappers(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()), true)); } @Override public QuickAccessElement[] computeElements(String query, IProgressMonitor monitor) { - this.usedLanguageServerWrappers = LanguageServiceAccessor.getStartedWrappers(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()), true); + final var usedLanguageServerWrappers = this.usedLanguageServerWrappers = LanguageServiceAccessor + .getStartedWrappers(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()), true); if (usedLanguageServerWrappers.isEmpty()) { return new QuickAccessElement[0]; } @@ -61,7 +65,7 @@ public QuickAccessElement[] computeElements(String query, IProgressMonitor monit try { CompletableFuture.allOf(usedLanguageServerWrappers.stream() - .map(w -> w.execute(ls -> ls.getWorkspaceService().symbol(params).thenAcceptAsync(symbols -> { + .map(w -> w.execute(ls -> ls.getWorkspaceService().symbol(params).thenAcceptAsync((@Nullable Either, List<@Nullable ? extends WorkspaceSymbol>> symbols) -> { if (symbols != null) { res.addAll(LSPSymbolInWorkspaceDialog.eitherToWorkspaceSymbols(symbols).stream().map(WorkspaceSymbolQuickAccessElement::new) .toList()); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/package-info.java new file mode 100644 index 000000000..3af9863ef --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.symbols; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyContentProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyContentProvider.java index 8ad0305c9..049961111 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyContentProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyContentProvider.java @@ -8,10 +8,13 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.typeHierarchy; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.lateNonNull; + import java.util.AbstractMap.SimpleEntry; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ITreeContentProvider; @@ -32,7 +35,7 @@ public class TypeHierarchyContentProvider implements ITreeContentProvider { private final LanguageServerDefinition lsDefinition; private final IDocument document; private boolean showSuperTypes; - private LanguageServerWrapper wrapper; + private LanguageServerWrapper wrapper = lateNonNull(); public TypeHierarchyContentProvider(LanguageServerDefinition lsDefinition, IDocument document, boolean showSuperTypes) { this.lsDefinition = lsDefinition; @@ -41,7 +44,7 @@ public TypeHierarchyContentProvider(LanguageServerDefinition lsDefinition, IDocu } @Override - public Object[] getElements(Object inputElement) { + public Object[] getElements(@Nullable Object inputElement) { if (inputElement instanceof ITextSelection textSelection) { try { Position position = LSPEclipseUtils.toPosition(textSelection.getOffset(), document); @@ -80,7 +83,7 @@ public Object[] getChildren(Object parentElement) { } @Override - public Object getParent(Object element) { + public @Nullable Object getParent(Object element) { return null; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyDialog.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyDialog.java index 1e9b7eb40..bcfb51f27 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyDialog.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyDialog.java @@ -9,7 +9,6 @@ package org.eclipse.lsp4e.operations.typeHierarchy; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; @@ -42,10 +41,10 @@ public class TypeHierarchyDialog extends PopupDialog { private static boolean showSuperTypes = true; private final LanguageServerDefinition lsDefinition; - private final @NonNull IDocument document; + private final IDocument document; private final ITextSelection textSelection; - public TypeHierarchyDialog(@NonNull Shell parentShell, ITextSelection textSelection, @NonNull IDocument document, @NonNull LanguageServerDefinition ls) { + public TypeHierarchyDialog(Shell parentShell, ITextSelection textSelection, IDocument document, LanguageServerDefinition ls) { super(parentShell, PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE, true, true, true, false, false, null, null); this.lsDefinition = ls; this.document = document; @@ -124,5 +123,3 @@ protected void configureShell(Shell shell) { shell.setSize(280, 300); } } - - diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyHandler.java index c8dcb02b6..91d9313ef 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyHandler.java @@ -11,6 +11,7 @@ import java.util.concurrent.CompletableFuture; import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.lsp4e.LSPEclipseUtils; @@ -31,7 +32,7 @@ protected void execute(ExecutionEvent event, ITextEditor editor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getTypeDefinitionProvider, editor -> true); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java index 77f6cb50e..1cea86359 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java @@ -8,6 +8,7 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.typeHierarchy; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StyledString; @@ -26,15 +27,15 @@ public String getText(Object element) { } @Override - public Image getImage(Object element) { + public @Nullable Image getImage(@Nullable Object element) { if (element instanceof TypeHierarchyItem item) { return LSPImages.imageFromSymbolKind(item.getKind()); } - return super.getImage(element); + return element == null ? null : super.getImage(element); } @Override - public StyledString getStyledText(Object element) { + public StyledString getStyledText(@Nullable Object element) { if (element instanceof TypeHierarchyItem item) { return new StyledString(item.getName()); } else if (element instanceof String s) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyView.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyView.java index 28d5df708..2a2bd8018 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyView.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyView.java @@ -11,6 +11,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.operations.typeHierarchy; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.lateNonNull; + import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; @@ -31,6 +33,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider; @@ -85,18 +88,18 @@ public class TypeHierarchyView extends ViewPart { - class SymbolsContainer { + private static final class SymbolsContainer { private final SymbolsModel symbolsModel; private volatile boolean isDirty = true; private boolean temporaryLoadedDocument = false; - private volatile URI uri; + private volatile URI uri = lateNonNull(); SymbolsContainer(URI uri) { this.symbolsModel = new SymbolsModel(); setUri(uri); } - public IDocument getDocument() { + public @Nullable IDocument getDocument() { IDocument document = null; var file = LSPEclipseUtils.getFileHandle(uri); if (file == null) { @@ -144,18 +147,20 @@ public void dispose() { } public static final String ID = "org.eclipse.lsp4e.operations.typeHierarchy.TypeHierarchyView"; //$NON-NLS-1$ - TypeHierarchyViewContentProvider contentProvider = new TypeHierarchyViewContentProvider(); - DecoratingStyledCellLabelProvider symbolsLabelProvider = new DecoratingStyledCellLabelProvider(new SymbolsLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), DecorationContext.DEFAULT_CONTEXT); + + private TypeHierarchyViewContentProvider contentProvider = new TypeHierarchyViewContentProvider(); + private DecoratingStyledCellLabelProvider symbolsLabelProvider = new DecoratingStyledCellLabelProvider(new SymbolsLabelProvider(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), DecorationContext.DEFAULT_CONTEXT); + // widgets - private PageBook pagebook; - private SashForm splitter; - private ViewForm memberViewForm; - private CLabel memberLabel; - private Label infoText; + private PageBook pagebook = lateNonNull(); + private SashForm splitter = lateNonNull(); + private ViewForm memberViewForm = lateNonNull(); + private CLabel memberLabel = lateNonNull(); + private Label infoText = lateNonNull(); // viewers - private TableViewer memberViewer; - protected TreeViewer treeViewer; + private TableViewer memberViewer = lateNonNull(); + private TreeViewer treeViewer = lateNonNull(); private HashMap cachedSymbols = new HashMap<>(); @@ -172,7 +177,7 @@ public void dirtyStateChanged(IFileBuffer buffer, boolean isDirty) { } @Override - public void underlyingFileMoved(IFileBuffer buffer, IPath path) { + public void underlyingFileMoved(@Nullable IFileBuffer buffer, IPath path) { var symbolsContainer = getSymbolsContainer(buffer); // check if this file has been cached: if (symbolsContainer != null && buffer != null) { @@ -186,7 +191,7 @@ public void underlyingFileMoved(IFileBuffer buffer, IPath path) { } } - private SymbolsContainer getSymbolsContainer(IFileBuffer buffer) { + private @Nullable SymbolsContainer getSymbolsContainer(@Nullable IFileBuffer buffer) { if (buffer != null) { return cachedSymbols.get(LSPEclipseUtils.toUri(buffer)); } @@ -273,7 +278,7 @@ private void onHierarchySelectionChanged(SelectionChangedEvent event) { } } - private void refreshMemberViewer(SymbolsContainer symbolsContainer, String typeName, boolean documentModified) { + private void refreshMemberViewer(@Nullable SymbolsContainer symbolsContainer, String typeName, boolean documentModified) { memberViewer.setInput(new PendingUpdateAdapter()); memberLabel.setImage(JFaceResources.getImage(ProgressManager.WAITING_JOB_KEY)); memberLabel.setText(Messages.outline_computingSymbols); @@ -369,7 +374,7 @@ private SymbolsContainer getSymbolsContainer(URI uri) { return cachedSymbols.computeIfAbsent(uri, entry -> new SymbolsContainer(uri)); } - private synchronized void refreshSymbols(SymbolsContainer symbolsContainer, boolean documentModified) { + private synchronized void refreshSymbols(@Nullable SymbolsContainer symbolsContainer, boolean documentModified) { if (symbolsContainer == null || (!symbolsContainer.isDirty && !documentModified)) { return; } @@ -407,7 +412,7 @@ private synchronized void refreshSymbols(SymbolsContainer symbolsContainer, bool } } - private DocumentSymbolWithURI getDocumentSymbol(SymbolsContainer symbolsContainer, String typeName) { + private @Nullable DocumentSymbolWithURI getDocumentSymbol(@Nullable SymbolsContainer symbolsContainer, String typeName) { if (symbolsContainer != null) { var elements = symbolsContainer.symbolsModel.getElements(); for (var element : elements) { @@ -429,7 +434,7 @@ private boolean isClass(SymbolKind kind) { return SymbolKind.Class.equals(kind) || SymbolKind.Struct.equals(kind) ; } - private DocumentSymbol searchInChildren(List children, String typeName) { + private @Nullable DocumentSymbol searchInChildren(@Nullable List children, String typeName) { if (children == null) { return null; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewContentProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewContentProvider.java index ffecaf251..1333fff36 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewContentProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewContentProvider.java @@ -15,7 +15,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.viewers.ITreeContentProvider; @@ -41,14 +41,14 @@ import org.eclipse.ui.PlatformUI; public class TypeHierarchyViewContentProvider implements ITreeContentProvider { - private TreeViewer treeViewer; - private LanguageServerWrapper languageServerWrapper; + private @Nullable TreeViewer treeViewer; + private @Nullable LanguageServerWrapper languageServerWrapper; private List hierarchyItems = Collections.emptyList(); public boolean showSuperTypes = true; - public IDocument document; + public @Nullable IDocument document; @Override - public Object[] getElements(Object inputElement) { + public Object[] getElements(@Nullable Object inputElement) { if (hierarchyItems.isEmpty()) { return new Object[] { Messages.TH_no_type_hierarchy }; } @@ -57,7 +57,7 @@ public Object[] getElements(Object inputElement) { @Override public Object[] getChildren(Object parentElement) { - if (parentElement instanceof TypeHierarchyItem parentItem) { + if (parentElement instanceof TypeHierarchyItem parentItem && languageServerWrapper != null) { try { return languageServerWrapper.execute(ls -> { TextDocumentService textDocumentService = ls.getTextDocumentService(); @@ -76,7 +76,7 @@ public Object[] getChildren(Object parentElement) { } @Override - public Object getParent(Object element) { + public @Nullable Object getParent(Object element) { return null; } @@ -86,7 +86,7 @@ public boolean hasChildren(Object element) { } @Override - public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { + public void inputChanged(final Viewer viewer, final @Nullable Object oldInput, final @Nullable Object newInput) { ITreeContentProvider.super.inputChanged(viewer, oldInput, newInput); if (newInput instanceof HierarchyViewInput viewInput) { @@ -108,7 +108,7 @@ public void inputChanged(final Viewer viewer, final Object oldInput, final Objec } - private void initialise(final @NonNull IDocument document, final int offset, TreeViewer viewer) throws BadLocationException { + private void initialise(final IDocument document, final int offset, TreeViewer viewer) throws BadLocationException { LanguageServerDocumentExecutor executor = LanguageServers.forDocument(document) .withCapability(ServerCapabilities::getTypeHierarchyProvider); if (!executor.anyMatching()) { @@ -123,6 +123,7 @@ private void initialise(final @NonNull IDocument document, final int offset, Tre hierarchyItems = p.second(); treeViewer = viewer; PlatformUI.getWorkbench().getDisplay().asyncExec(() -> { + final var treeViewer = this.treeViewer; if (treeViewer != null) { treeViewer.refresh(); treeViewer.expandToLevel(2); @@ -142,7 +143,7 @@ private void initialise(final @NonNull IDocument document, final int offset, Tre } - private static TypeHierarchyPrepareParams toTypeHierarchyPrepareParams(int offset, final @NonNull IDocument document) throws BadLocationException { + private static TypeHierarchyPrepareParams toTypeHierarchyPrepareParams(int offset, final IDocument document) throws BadLocationException { Position position = LSPEclipseUtils.toPosition(offset, document); TextDocumentIdentifier documentIdentifier = LSPEclipseUtils.toTextDocumentIdentifier(document); return new TypeHierarchyPrepareParams(documentIdentifier, position); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewHandler.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewHandler.java index 64093e213..417ac7847 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewHandler.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyViewHandler.java @@ -12,6 +12,7 @@ package org.eclipse.lsp4e.operations.typeHierarchy; import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.lsp4e.LSPEclipseUtils; @@ -45,7 +46,7 @@ protected void execute(ExecutionEvent event, ITextEditor editor) { } @Override - public void setEnabled(Object evaluationContext) { + public void setEnabled(@Nullable Object evaluationContext) { setEnabled(ServerCapabilities::getTypeHierarchyProvider, this::hasSelection); } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeMemberContentProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeMemberContentProvider.java index df7ef47dc..2bdd1f9dc 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeMemberContentProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeMemberContentProvider.java @@ -14,7 +14,7 @@ import java.net.URI; import java.util.List; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithURI; import org.eclipse.lsp4j.DocumentSymbol; @@ -23,14 +23,14 @@ public class TypeMemberContentProvider implements IStructuredContentProvider { private static final Object[] NO_CHILDREN = new Object[0]; @Override - public Object[] getElements(Object inputElement) { + public Object[] getElements(@Nullable Object inputElement) { if (inputElement instanceof DocumentSymbolWithURI symbolContainer) { return toContainer(symbolContainer.symbol.getChildren(), symbolContainer.uri); } return NO_CHILDREN; } - private Object[] toContainer(List symbols, @NonNull URI uri) { + private Object[] toContainer(@Nullable List symbols, URI uri) { if (symbols != null) { var container = new DocumentSymbolWithURI[symbols.size()]; for (int i = 0; i < symbols.size(); i++) { diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/package-info.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/package-info.java new file mode 100644 index 000000000..e559e6efd --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/package-info.java @@ -0,0 +1,6 @@ +@NonNullByDefault({ ARRAY_CONTENTS, PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT }) +package org.eclipse.lsp4e.operations.typeHierarchy; + +import static org.eclipse.jdt.annotation.DefaultLocation.*; + +import org.eclipse.jdt.annotation.NonNullByDefault;