Skip to content

Commit

Permalink
fix: Argument for @NotNull parameter 'file' of
Browse files Browse the repository at this point in the history
com/intellij/openapi/vfs/VfsUtilCore.virtualToIoFile must not be null

Fixes #1228

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr authored and fbricon committed Oct 18, 2023
1 parent 30a70eb commit f07ef8c
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 60 deletions.
53 changes: 38 additions & 15 deletions src/main/java/com/redhat/devtools/intellij/lsp4ij/LSPIJUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ public static Language getFileLanguage(@Nonnull VirtualFile file, Project projec
}

private static <T extends TextDocumentPositionParams> T toTextDocumentPositionParamsCommon(T param, int offset, Document document) {
URI uri = toUri(document);
Position start = toPosition(offset, document);
param.setPosition(start);
TextDocumentIdentifier id = new TextDocumentIdentifier();
URI uri = toUri(document);
if (uri != null) {
id.setUri(uri.toASCIIString());
}
Expand All @@ -106,7 +106,19 @@ public static HoverParams toHoverParams(int offset, Document document) {
return toTextDocumentPositionParamsCommon(new HoverParams(), offset, document);
}

public static URI toUri(File file) {

/**
* Returns the Uri of the virtual file corresponding to the specified document.
*
* @param document the document for which the virtual file is requested.
* @return the Uri of the file, or null if the document wasn't created from a virtual file.
*/
public static @Nullable URI toUri(@NotNull Document document) {
VirtualFile file = getFile(document);
return file != null ? toUri(file) : null;
}

public static @NotNull URI toUri(@NotNull File file) {
// URI scheme specified by language server protocol and LSP
try {
return new URI("file", "", file.getAbsoluteFile().toURI().getPath(), null); //$NON-NLS-1$ //$NON-NLS-2$
Expand All @@ -116,35 +128,46 @@ public static URI toUri(File file) {
}
}

public static URI toUri(PsiFile file) {
return toUri(file.getVirtualFile());
public static @Nullable URI toUri(@NotNull PsiFile psiFile) {
VirtualFile file = getFile(psiFile);
return file != null ? toUri(file) : null;
}

public static URI toUri(VirtualFile file) {
public static @NotNull URI toUri(@NotNull VirtualFile file) {
return toUri(VfsUtilCore.virtualToIoFile(file));
}

public static String toUriAsString(PsiFile file) {
return toUriAsString(file.getVirtualFile());
public static @Nullable String toUriAsString(@NotNull PsiFile psFile) {
VirtualFile file = psFile.getVirtualFile();
return file != null ? toUriAsString(file) : null;
}

public static String toUriAsString(VirtualFile file) {
public static @NotNull String toUriAsString(@NotNull VirtualFile file) {
String protocol = file.getFileSystem() != null ? file.getFileSystem().getProtocol() : null;
if (JAR_PROTOCOL.equals(protocol) || JRT_PROTOCOL.equals(protocol)) {
return VfsUtilCore.convertToURL(file.getUrl()).toExternalForm();
}
return toUri(VfsUtilCore.virtualToIoFile(file)).toASCIIString();
}

public static URI toUri(Document document) {
VirtualFile file = getFile(document);
return file != null ? toUri(file) : null;
}

public static @Nullable VirtualFile getFile(Document document) {
return FileDocumentManager.getInstance().getFile(document);
/**
* Returns the virtual file corresponding to the specified document.
*
* @param document the document for which the virtual file is requested.
* @return the file, or null if the document wasn't created from a virtual file.
*/
public static @Nullable VirtualFile getFile(@NotNull Document document) {
if (ApplicationManager.getApplication().isReadAccessAllowed()) {
return FileDocumentManager.getInstance().getFile(document);
}
return ReadAction.compute(() -> FileDocumentManager.getInstance().getFile(document));
}

/**
* Returns the virtual file corresponding to the PSI file.
*
* @return the virtual file, or {@code null} if the file exists only in memory.
*/
public static @Nullable VirtualFile getFile(@NotNull PsiElement element) {
PsiFile psFile = element.getContainingFile();
return psFile != null ? psFile.getVirtualFile() : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,23 @@ public class LSPCompletionContributor extends CompletionContributor {

@Override
public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
Document document = parameters.getEditor().getDocument();
Editor editor = parameters.getEditor();
PsiFile psiFile = parameters.getOriginalFile();
VirtualFile file = psiFile.getVirtualFile();
if (file == null) {
return;
}

Editor editor = parameters.getEditor();
Document document = editor.getDocument();
Project project = psiFile.getProject();
int offset = parameters.getOffset();
VirtualFile file = psiFile.getVirtualFile();
URI uri = LSPIJUtils.toUri(file);

ProgressManager.checkCanceled();

final CancellationSupport cancellationSupport = new CancellationSupport();
try {
CompletableFuture<List<LanguageServerItem>> completionLanguageServersFuture = initiateLanguageServers(project, file);
CompletableFuture<List<LanguageServerItem>> completionLanguageServersFuture = initiateLanguageServers(file, project);
cancellationSupport.execute(completionLanguageServersFuture);
ProgressManager.checkCanceled();

Expand Down Expand Up @@ -171,7 +176,7 @@ private static LookupElement createErrorProposal(int offset, Exception ex) {
return LookupElementBuilder.create("Error while computing completion", "");
}

private static CompletableFuture<List<LanguageServerItem>> initiateLanguageServers(Project project, VirtualFile file) {
private static CompletableFuture<List<LanguageServerItem>> initiateLanguageServers(@NotNull VirtualFile file, @NotNull Project project) {
return LanguageServiceAccessor.getInstance(project).getLanguageServers(file,
capabilities -> {
CompletionOptions provider = capabilities.getCompletionProvider();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
Expand Down Expand Up @@ -55,10 +56,6 @@ public class LSPDocumentLinkAnnotator extends ExternalAnnotator<List<LSPVirtualF
@Nullable
@Override
public List<LSPVirtualFileData> collectInformation(@NotNull PsiFile psiFile, @NotNull Editor editor, boolean hasErrors) {
URI uri = LSPIJUtils.toUri(editor.getDocument());
if (uri == null) {
return null;
}
Document document = editor.getDocument();
VirtualFile file = LSPIJUtils.getFile(document);
if (file == null) {
Expand All @@ -68,10 +65,13 @@ public List<LSPVirtualFileData> collectInformation(@NotNull PsiFile psiFile, @No
final CancellationSupport cancellationSupport = new CancellationSupport();
try {
ProgressManager.checkCanceled();

URI uri = LSPIJUtils.toUri(file);
DocumentLinkParams params = new DocumentLinkParams(LSPIJUtils.toTextDocumentIdentifier(uri));

Project project = editor.getProject();
BlockingDeque<Pair<List<DocumentLink>, LanguageServerWrapper>> documentLinks = new LinkedBlockingDeque<>();
CompletableFuture<Void> future = LanguageServiceAccessor.getInstance(editor.getProject()).getLanguageServers(file,
CompletableFuture<Void> future = LanguageServiceAccessor.getInstance(project).getLanguageServers(file,
capabilities -> capabilities.getDocumentLinkProvider() != null)
.thenAcceptAsync(languageServers ->
cancellationSupport.execute(CompletableFuture.allOf(languageServers.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,22 @@ private List<LSPHighlightPsiElement> getTargets(Editor editor, PsiFile psiFile)
if (file == null) {
return Collections.emptyList();
}
URI uri = LSPIJUtils.toUri(file);
List<LSPHighlightPsiElement> elements = new ArrayList<>();
final CancellationSupport cancellationSupport = new CancellationSupport();
try {
int offset = TargetElementUtil.adjustOffset(psiFile, editor.getDocument(), editor.getCaretModel().getOffset());
Document document = editor.getDocument();
int offset = TargetElementUtil.adjustOffset(psiFile, document, editor.getCaretModel().getOffset());
Position position = LSPIJUtils.toPosition(offset, document);

ProgressManager.checkCanceled();
TextDocumentIdentifier identifier = new TextDocumentIdentifier(uri.toString());

String uri = LSPIJUtils.toUriAsString(file);
TextDocumentIdentifier identifier = new TextDocumentIdentifier(uri);
DocumentHighlightParams params = new DocumentHighlightParams(identifier, position);
BlockingDeque<DocumentHighlight> highlights = new LinkedBlockingDeque<>();

CompletableFuture<Void> future = LanguageServiceAccessor.getInstance(editor.getProject())
.getLanguageServers(psiFile.getVirtualFile(), capabilities -> LSPIJUtils.hasCapability(capabilities.getDocumentHighlightProvider()))
.getLanguageServers(file, capabilities -> LSPIJUtils.hasCapability(capabilities.getDocumentHighlightProvider()))
.thenAcceptAsync(languageServers ->
cancellationSupport.execute(CompletableFuture.allOf(languageServers.stream()
.map(languageServer -> cancellationSupport.execute(languageServer.getServer().getTextDocumentService().documentHighlight(params)))
Expand Down Expand Up @@ -97,4 +98,4 @@ private List<LSPHighlightPsiElement> getTargets(Editor editor, PsiFile psiFile)
return elements;

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,39 +51,41 @@ public class LSPGotoDeclarationHandler implements GotoDeclarationHandler {
@Nullable
@Override
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement sourceElement, int offset, Editor editor) {
URI uri = LSPIJUtils.toUri(editor.getDocument());
if (uri != null) {
VirtualFile file = LSPIJUtils.getFile(sourceElement);
DefinitionParams params = new DefinitionParams(LSPIJUtils.toTextDocumentIdentifier(uri), LSPIJUtils.toPosition(offset, editor.getDocument()));
Set<PsiElement> targets = new HashSet<>();
final CancellationSupport cancellationSupport = new CancellationSupport();
try {
LanguageServiceAccessor.getInstance(editor.getProject())
.getLanguageServers(file, capabilities -> LSPIJUtils.hasCapability(capabilities.getDefinitionProvider()))
.thenComposeAsync(languageServers ->
cancellationSupport.execute(
CompletableFuture.allOf(
languageServers
.stream()
.map(server ->
cancellationSupport.execute(server.getServer().getTextDocumentService().definition(params))
.thenAcceptAsync(definitions -> targets.addAll(toElements(editor.getProject(), definitions))))
.toArray(CompletableFuture[]::new))))
.get(1_000, TimeUnit.MILLISECONDS);
} catch (ResponseErrorException | ExecutionException | CancellationException e) {
// do not report error if the server has cancelled the request
if (!CancellationUtil.isRequestCancelledException(e)) {
LOGGER.warn(e.getLocalizedMessage(), e);
}
} catch (TimeoutException e) {
LOGGER.warn(e.getLocalizedMessage(), e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
VirtualFile file = LSPIJUtils.getFile(sourceElement);
if (file == null) {
return PsiElement.EMPTY_ARRAY;
}
URI uri = LSPIJUtils.toUri(file);
Document document = editor.getDocument();
DefinitionParams params = new DefinitionParams(LSPIJUtils.toTextDocumentIdentifier(uri), LSPIJUtils.toPosition(offset, document));
Set<PsiElement> targets = new HashSet<>();
final CancellationSupport cancellationSupport = new CancellationSupport();
try {
Project project = editor.getProject();
LanguageServiceAccessor.getInstance(project)
.getLanguageServers(file, capabilities -> LSPIJUtils.hasCapability(capabilities.getDefinitionProvider()))
.thenComposeAsync(languageServers ->
cancellationSupport.execute(
CompletableFuture.allOf(
languageServers
.stream()
.map(server ->
cancellationSupport.execute(server.getServer().getTextDocumentService().definition(params))
.thenAcceptAsync(definitions -> targets.addAll(toElements(project, definitions))))
.toArray(CompletableFuture[]::new))))
.get(1_000, TimeUnit.MILLISECONDS);
} catch (ResponseErrorException | ExecutionException | CancellationException e) {
// do not report error if the server has cancelled the request
if (!CancellationUtil.isRequestCancelledException(e)) {
LOGGER.warn(e.getLocalizedMessage(), e);
}
return targets.toArray(new PsiElement[targets.size()]);
} catch (TimeoutException e) {
LOGGER.warn(e.getLocalizedMessage(), e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.warn(e.getLocalizedMessage(), e);
}
return new PsiElement[0];
return targets.toArray(new PsiElement[targets.size()]);
}

private List<PsiElement> toElements(Project project, Either<List<? extends Location>, List<? extends LocationLink>> definitions) {
Expand Down

0 comments on commit f07ef8c

Please sign in to comment.