Skip to content

Commit ed7caa0

Browse files
committed
perf: use PsiFile instead of using VirtualFile
Signed-off-by: azerr <[email protected]>
1 parent 2c3502d commit ed7caa0

File tree

37 files changed

+125
-102
lines changed

37 files changed

+125
-102
lines changed

src/main/java/com/redhat/devtools/lsp4ij/ConnectDocumentToLanguageServerSetupParticipant.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile f
6565
}
6666

6767
private static void connectToLanguageServer(@NotNull VirtualFile file, @NotNull Project project) {
68-
// Force the start of all languages servers mapped with the given file
69-
// Server capabilities filter is set to null to avoid waiting
70-
// for the start of the server when server capabilities are checked
71-
LanguageServiceAccessor.getInstance(project)
72-
.getLanguageServers(file, null, null);
68+
PsiFile psiFile = LSPIJUtils.getPsiFile(file, project);
69+
if (psiFile != null) {
70+
// Force the start of all languages servers mapped with the given file
71+
// Server capabilities filter is set to null to avoid waiting
72+
// for the start of the server when server capabilities are checked
73+
LanguageServiceAccessor.getInstance(project)
74+
.getLanguageServers(psiFile, null, null);
75+
}
7376
}
7477

7578
}

src/main/java/com/redhat/devtools/lsp4ij/LSPIJEditorUtils.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ private ClientFeaturesBasedCommenter(@NotNull PsiFile file) {
400400
@Nullable
401401
private static LSPClientFeatures getClientFeatures(@NotNull PsiFile file) {
402402
CompletableFuture<List<LanguageServerItem>> languageServersFuture = LanguageServiceAccessor.getInstance(file.getProject()).getLanguageServers(
403-
file.getVirtualFile(),
403+
file,
404404
clientFeatures -> StringUtil.isNotEmpty(clientFeatures.getLineCommentPrefix(file)) ||
405405
StringUtil.isNotEmpty(clientFeatures.getBlockCommentPrefix(file)) ||
406406
StringUtil.isNotEmpty(clientFeatures.getBlockCommentSuffix(file)),

src/main/java/com/redhat/devtools/lsp4ij/LSPIJUtils.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,16 @@ private static Language doGetFileLanguage(@NotNull VirtualFile file, @NotNull Pr
565565
}
566566

567567

568+
/**
569+
* Returns the virtual file corresponding to the PSI file.
570+
*
571+
* @param psiFile the PSI file
572+
* @return the virtual file, or {@code null} if the file exists only in memory.
573+
*/
574+
public static @Nullable VirtualFile getFile(@NotNull PsiFile psiFile) {
575+
return psiFile.getVirtualFile();
576+
}
577+
568578
/**
569579
* Returns the virtual file corresponding to the PSI element.
570580
*
@@ -573,7 +583,7 @@ private static Language doGetFileLanguage(@NotNull VirtualFile file, @NotNull Pr
573583
*/
574584
public static @Nullable VirtualFile getFile(@NotNull PsiElement element) {
575585
PsiFile psFile = element.getContainingFile();
576-
return psFile != null ? psFile.getVirtualFile() : null;
586+
return psFile != null ? getFile(psFile) : null;
577587
}
578588

579589
/**

src/main/java/com/redhat/devtools/lsp4ij/LanguageServersRegistry.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,9 @@ private static String getServerNotAvailableMessage(ServerMapping mapping) {
290290
* @return the {@link LanguageServerDefinition}s <strong>directly</strong> associated to the given content-type.
291291
* This does <strong>not</strong> include the one that match transitively as per content-type hierarchy
292292
*/
293-
List<LanguageServerFileAssociation> findLanguageServerDefinitionFor(final @Nullable Language language, @Nullable FileType fileType, @NotNull VirtualFile file) {
293+
List<LanguageServerFileAssociation> findLanguageServerDefinitionFor(final @Nullable Language language, @Nullable FileType fileType, @NotNull String fileName) {
294294
return fileAssociations.stream()
295-
.filter(mapping -> mapping.match(language, fileType, file.getName()))
295+
.filter(mapping -> mapping.match(language, fileType, fileName))
296296
.collect(Collectors.toList());
297297
}
298298

src/main/java/com/redhat/devtools/lsp4ij/LanguageServiceAccessor.java

+27-23
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.intellij.openapi.project.Project;
2222
import com.intellij.openapi.project.ProjectManager;
2323
import com.intellij.openapi.vfs.VirtualFile;
24+
import com.intellij.psi.PsiFile;
2425
import com.intellij.util.concurrency.AppExecutorUtil;
2526
import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures;
2627
import com.redhat.devtools.lsp4ij.internal.editor.EditorFeatureManager;
@@ -153,11 +154,13 @@ void sendDidOpenAndRefreshEditorFeatureForOpenedFiles(@NotNull LanguageServerDef
153154
@NotNull Project project) {
154155
VirtualFile[] files = FileEditorManager.getInstance(project).getOpenFiles();
155156
for (VirtualFile file : files) {
156-
sendDidOpenAndRefreshEditorFeatureFor(file, serverDefinition);
157+
// TODO : revisit that
158+
PsiFile psiFile = LSPIJUtils.getPsiFile(file, project);
159+
sendDidOpenAndRefreshEditorFeatureFor(psiFile, serverDefinition);
157160
}
158161
}
159162

160-
private void sendDidOpenAndRefreshEditorFeatureFor(@NotNull VirtualFile file,
163+
private void sendDidOpenAndRefreshEditorFeatureFor(@NotNull PsiFile file,
161164
@NotNull LanguageServerDefinition serverDefinition) {
162165
ReadAction.nonBlocking(() -> {
163166
// Try to send a textDocument/didOpen notification if the file is associated to the language server definition
@@ -185,13 +188,13 @@ private void sendDidOpenAndRefreshEditorFeatureFor(@NotNull VirtualFile file,
185188
* @param filter the filter.
186189
* @return true if the given file matches one of started language server with the given filter and false otherwise.
187190
*/
188-
public boolean hasAny(@NotNull VirtualFile file,
191+
public boolean hasAny(@NotNull PsiFile file,
189192
@NotNull Predicate<LanguageServerWrapper> filter) {
190193
var startedServers = getStartedServers();
191194
if (startedServers.isEmpty()) {
192195
return false;
193196
}
194-
MatchedLanguageServerDefinitions mappings = getMatchedLanguageServerDefinitions(file, project, true);
197+
MatchedLanguageServerDefinitions mappings = getMatchedLanguageServerDefinitions(file, true);
195198
if (mappings == MatchedLanguageServerDefinitions.NO_MATCH) {
196199
return false;
197200
}
@@ -243,19 +246,19 @@ public boolean hasAny(@NotNull VirtualFile file,
243246
}
244247

245248
@NotNull
246-
public CompletableFuture<@NotNull List<LanguageServerItem>> getLanguageServers(@NotNull VirtualFile file,
249+
public CompletableFuture<@NotNull List<LanguageServerItem>> getLanguageServers(@NotNull PsiFile file,
247250
@Nullable Predicate<LSPClientFeatures> beforeStartingServerFilter,
248251
@Nullable Predicate<LSPClientFeatures> afterStartingServerFilter) {
249252
return getLanguageServers(file, beforeStartingServerFilter, afterStartingServerFilter, null);
250253
}
251254

252255
@NotNull
253-
CompletableFuture<@NotNull List<LanguageServerItem>> getLanguageServers(@NotNull VirtualFile file,
256+
CompletableFuture<@NotNull List<LanguageServerItem>> getLanguageServers(@NotNull PsiFile psiFile,
254257
@Nullable Predicate<LSPClientFeatures> beforeStartingServerFilter,
255258
@Nullable Predicate<LSPClientFeatures> afterStartingServerFilter,
256259
@Nullable LanguageServerDefinition matchServerDefinition) {
257260
// Collect started (or not) language servers which matches the given file.
258-
CompletableFuture<Collection<LanguageServerWrapper>> matchedServers = getMatchedLanguageServersWrappers(file, matchServerDefinition, beforeStartingServerFilter);
261+
CompletableFuture<Collection<LanguageServerWrapper>> matchedServers = getMatchedLanguageServersWrappers(psiFile, matchServerDefinition, beforeStartingServerFilter);
259262
var matchedServersNow= matchedServers.getNow(Collections.emptyList());
260263
if (matchedServers.isDone() && matchedServersNow.isEmpty()) {
261264
// None language servers matches the given file
@@ -269,7 +272,8 @@ public boolean hasAny(@NotNull VirtualFile file,
269272
// LSP document listener to manage didOpen, didChange, etc.
270273
boolean writeAccessAllowed = ApplicationManager.getApplication().isWriteAccessAllowed();
271274
boolean readAccessAllowed = ApplicationManager.getApplication().isReadAccessAllowed();
272-
Document document = readAccessAllowed || (!writeAccessAllowed) ? LSPIJUtils.getDocument(file) : null;
275+
Document document = readAccessAllowed || (!writeAccessAllowed) ? LSPIJUtils.getDocument(psiFile) : null;
276+
var file = psiFile.getVirtualFile();
273277

274278
// Try to get document, languageId information (used by didOpen) for each matched language server wrapper
275279
// since here we should be in Read Action allowed
@@ -356,10 +360,10 @@ public void projectClosing(Project project) {
356360

357361
@NotNull
358362
private CompletableFuture<Collection<LanguageServerWrapper>> getMatchedLanguageServersWrappers(
359-
@NotNull VirtualFile file,
363+
@NotNull PsiFile file,
360364
@Nullable LanguageServerDefinition matchServerDefinition,
361365
@Nullable Predicate<LSPClientFeatures> beforeStartingServerFilter) {
362-
MatchedLanguageServerDefinitions mappings = getMatchedLanguageServerDefinitions(file, project, false);
366+
MatchedLanguageServerDefinitions mappings = getMatchedLanguageServerDefinitions(file, false);
363367
if (mappings == MatchedLanguageServerDefinitions.NO_MATCH) {
364368
// There are no mapping for the given file
365369
return CompletableFuture.completedFuture(Collections.emptyList());
@@ -393,22 +397,23 @@ private CompletableFuture<Collection<LanguageServerWrapper>> getMatchedLanguageS
393397
/**
394398
* Get or create a language server wrapper for the given server definitions and add then to the given matched servers.
395399
*
396-
* @param file the file.
400+
* @param psiFile the file.
397401
* @param serverDefinitions the server definitions.
398402
* @param matchedServers the list to update with get/created language server.
399403
* @param beforeStartingServerFilter
400404
*/
401-
private void collectLanguageServersFromDefinition(@Nullable VirtualFile file,
405+
private void collectLanguageServersFromDefinition(@Nullable PsiFile psiFile,
402406
@NotNull Set<LanguageServerDefinition> serverDefinitions,
403407
@NotNull Set<LanguageServerWrapper> matchedServers,
404408
@Nullable Predicate<LSPClientFeatures> beforeStartingServerFilter) {
409+
var file = psiFile.getVirtualFile();
405410
synchronized (startedServers) {
406411
for (var serverDefinition : serverDefinitions) {
407412
boolean useExistingServer = false;
408413
// Loop for started language servers
409414
for (var startedServer : startedServers) {
410415
if (startedServer.getServerDefinition().equals(serverDefinition)
411-
&& (file == null || startedServer.canOperate(file))
416+
&& (psiFile == null || startedServer.canOperate(file))
412417
&& (beforeStartingServerFilter == null || beforeStartingServerFilter.test(startedServer.getClientFeatures()))) {
413418
// A started language server match the file, use it
414419
matchedServers.add(startedServer);
@@ -466,26 +471,25 @@ public CompletableFuture<Set<LanguageServerDefinition>> getAsyncMatched() {
466471
/**
467472
* Returns the matched language server definitions for the given file.
468473
*
469-
* @param file the file.
470-
* @param fileProject the file project.
474+
* @param psiFile the file.
471475
* @param ignoreMatch true if {@link DocumentMatcher} must be ignored when mapping matches the given file and false otherwise.
472476
* @return the matched language server definitions for the given file.
473477
*/
474-
private MatchedLanguageServerDefinitions getMatchedLanguageServerDefinitions(@NotNull VirtualFile file,
475-
@NotNull Project fileProject,
478+
private MatchedLanguageServerDefinitions getMatchedLanguageServerDefinitions(@NotNull PsiFile psiFile,
476479
boolean ignoreMatch) {
477480

481+
var file = psiFile.getVirtualFile();
478482
Set<LanguageServerDefinition> syncMatchedDefinitions = null;
479483
Set<LanguageServerFileAssociation> asyncMatchedDefinitions = null;
480484

481485
// look for running language servers via content-type
482486
Queue<Object> languages = new LinkedList<>();
483487
Set<Object> processedContentTypes = new HashSet<>();
484-
Language language = LSPIJUtils.getFileLanguage(file, project);
488+
Language language = psiFile.getLanguage();
485489
if (language != null) {
486490
languages.add(language);
487491
}
488-
FileType fileType = file.getFileType();
492+
FileType fileType = psiFile.getFileType();
489493
languages.add(fileType);
490494

491495
while (!languages.isEmpty()) {
@@ -502,7 +506,7 @@ private MatchedLanguageServerDefinitions getMatchedLanguageServerDefinitions(@No
502506
}
503507
// Loop for server/language mapping
504508
for (LanguageServerFileAssociation mapping : LanguageServersRegistry.getInstance()
505-
.findLanguageServerDefinitionFor(currentLanguage, currentFileType, file)) {
509+
.findLanguageServerDefinitionFor(currentLanguage, currentFileType, file.getName())) {
506510
if (mapping == null || !mapping.isEnabled(project) || (syncMatchedDefinitions != null && syncMatchedDefinitions.contains(mapping.getServerDefinition()))) {
507511
// the mapping is disabled
508512
// or the server definition has been already added
@@ -514,7 +518,7 @@ private MatchedLanguageServerDefinitions getMatchedLanguageServerDefinitions(@No
514518
}
515519
syncMatchedDefinitions.add(mapping.getServerDefinition());
516520
} else {
517-
if (mapping.shouldBeMatchedAsynchronously(fileProject)) {
521+
if (mapping.shouldBeMatchedAsynchronously(project)) {
518522
// Async mapping
519523
// Mapping must be done asynchronously because the match of DocumentMatcher of the mapping need to be done asynchronously
520524
// This usecase comes from for instance when custom match need to collect classes from the Java project and requires read only action.
@@ -524,7 +528,7 @@ private MatchedLanguageServerDefinitions getMatchedLanguageServerDefinitions(@No
524528
asyncMatchedDefinitions.add(mapping);
525529
} else {
526530
// Sync mapping
527-
if (match(file, fileProject, mapping)) {
531+
if (match(file, project, mapping)) {
528532
if (syncMatchedDefinitions == null) {
529533
syncMatchedDefinitions = new HashSet<>();
530534
}
@@ -543,7 +547,7 @@ private MatchedLanguageServerDefinitions getMatchedLanguageServerDefinitions(@No
543547
async = CompletableFuture.allOf(asyncMatchedDefinitions
544548
.stream()
545549
.map(mapping -> mapping
546-
.matchAsync(file, fileProject)
550+
.matchAsync(file, project)
547551
.thenApply(result -> {
548552
if (result) {
549553
serverDefinitions.add(mapping.getServerDefinition());

src/main/java/com/redhat/devtools/lsp4ij/client/features/EditorBehaviorFeature.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public boolean isEnableSemanticTokensFileViewProvider(@NotNull PsiFile file) {
121121
*/
122122
public static boolean enableStringLiteralImprovements(@NotNull PsiFile file) {
123123
return LanguageServiceAccessor.getInstance(file.getProject()).hasAny(
124-
file.getVirtualFile(),
124+
file,
125125
ls -> ls.getClientFeatures().getEditorBehaviorFeature().isEnableStringLiteralImprovements(file)
126126
);
127127
}
@@ -135,7 +135,7 @@ public static boolean enableStringLiteralImprovements(@NotNull PsiFile file) {
135135
*/
136136
public static boolean enableStatementTerminatorImprovements(@NotNull PsiFile file) {
137137
return LanguageServiceAccessor.getInstance(file.getProject()).hasAny(
138-
file.getVirtualFile(),
138+
file,
139139
ls -> ls.getClientFeatures().getEditorBehaviorFeature().isEnableStatementTerminatorImprovements(file)
140140
);
141141
}
@@ -149,7 +149,7 @@ public static boolean enableStatementTerminatorImprovements(@NotNull PsiFile fil
149149
*/
150150
public static boolean enableEnterBetweenBracesFix(@NotNull PsiFile file) {
151151
return LanguageServiceAccessor.getInstance(file.getProject()).hasAny(
152-
file.getVirtualFile(),
152+
file,
153153
ls -> ls.getClientFeatures().getEditorBehaviorFeature().isEnableEnterBetweenBracesFix(file)
154154
);
155155
}
@@ -164,7 +164,7 @@ public static boolean enableEnterBetweenBracesFix(@NotNull PsiFile file) {
164164
*/
165165
public static boolean enableTextMateNestedBracesImprovements(@NotNull PsiFile file) {
166166
return LanguageServiceAccessor.getInstance(file.getProject()).hasAny(
167-
file.getVirtualFile(),
167+
file,
168168
ls -> ls.getClientFeatures().getEditorBehaviorFeature().isEnableTextMateNestedBracesImprovements(file)
169169
);
170170
}
@@ -177,7 +177,7 @@ public static boolean enableTextMateNestedBracesImprovements(@NotNull PsiFile fi
177177
*/
178178
public static boolean enableSemanticTokensFileViewProvider(@NotNull PsiFile file) {
179179
return LanguageServiceAccessor.getInstance(file.getProject()).hasAny(
180-
file.getVirtualFile(),
180+
file,
181181
ls -> ls.getClientFeatures().getEditorBehaviorFeature().isEnableSemanticTokensFileViewProvider(file)
182182
);
183183
}

src/main/java/com/redhat/devtools/lsp4ij/client/indexing/ProjectIndexingStrategyBase.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package com.redhat.devtools.lsp4ij.client.indexing;
1212

1313
import com.intellij.openapi.project.Project;
14+
import com.redhat.devtools.lsp4ij.LSPIJUtils;
1415
import com.redhat.devtools.lsp4ij.LanguageServiceAccessor;
1516
import com.redhat.devtools.lsp4ij.internal.editor.EditorFeatureManager;
1617
import com.redhat.devtools.lsp4ij.internal.editor.EditorFeatureType;
@@ -96,10 +97,10 @@ private void refreshEditorsFeaturesIfNeeded(ProjectIndexingManager manager) {
9697
while (!manager.filesToRefresh.isEmpty()) {
9798
var files = new HashSet<>(manager.filesToRefresh);
9899
for (var file : files) {
99-
100+
var psiFile = LSPIJUtils.getPsiFile(file, manager.project);
100101
// Try to send a textDocument/didOpen notification if the file is associated to the language server definition
101102
LanguageServiceAccessor.getInstance(manager.project)
102-
.getLanguageServers(file, null, null)
103+
.getLanguageServers(psiFile, null, null)
103104
.thenAccept(servers -> {
104105
// textDocument/didOpen notification has been sent
105106
if (servers.isEmpty()) {
@@ -109,7 +110,7 @@ private void refreshEditorsFeaturesIfNeeded(ProjectIndexingManager manager) {
109110
// Refresh all features (code vision, inlay hints, folding,etc)
110111
// of editors which edit the current file.
111112
EditorFeatureManager.getInstance(manager.project)
112-
.refreshEditorFeature(file, EditorFeatureType.ALL, true);
113+
.refreshEditorFeature(psiFile, EditorFeatureType.ALL, true);
113114

114115
});
115116
}

0 commit comments

Comments
 (0)