mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
matching meta-languages: make thread safe, memory optimization: do not store Application reference/empty collections in the majority case of a language without matching meta-languages
GitOrigin-RevId: e2b2c7735649556ef1becfef26f111477c4d9d71
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8a8aceb216
commit
2113578e90
@@ -1,14 +1,13 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang;
|
||||
|
||||
import com.intellij.ReviseWhenPortedToJDK;
|
||||
import com.intellij.lexer.Lexer;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
@@ -19,7 +18,6 @@ import com.intellij.util.containers.JBIterable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -157,14 +155,13 @@ public final class LanguageUtil {
|
||||
return provider.getBaseLanguage();
|
||||
}
|
||||
|
||||
private static final Key<Pair<SoftReference<Application>,Set<MetaLanguage>>> MATCHING_LANGUAGES = Key.create("language.matching");
|
||||
private static final Key<Collection<MetaLanguage>> MATCHING_META_LANGUAGES = Key.create("MATCHING_META_LANGUAGES");
|
||||
|
||||
@ReviseWhenPortedToJDK(value = "9", description = "use List.of() instead of deprecated immutableList()")
|
||||
static @NotNull Collection<MetaLanguage> matchingMetaLanguages(@NotNull Language language) {
|
||||
// A mock application may cause incorrect caching during tests. It does not fire extension point removed events.
|
||||
// Ensure that we have cached against correct application.
|
||||
Pair<SoftReference<Application>, Set<MetaLanguage>> cached = language.getUserData(MATCHING_LANGUAGES);
|
||||
if (cached != null && cached.first.get() == ApplicationManager.getApplication()) {
|
||||
return cached.second;
|
||||
Collection<MetaLanguage> cached = language.getUserData(MATCHING_META_LANGUAGES);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (!ApplicationManager.getApplication().getExtensionArea().hasExtensionPoint(MetaLanguage.EP_NAME)) {
|
||||
@@ -172,26 +169,25 @@ public final class LanguageUtil {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Set<MetaLanguage> result;
|
||||
Collection<MetaLanguage> toCache;
|
||||
if (language instanceof MetaLanguage) {
|
||||
result = Collections.emptySet();
|
||||
toCache = Collections.emptySet();
|
||||
}
|
||||
else {
|
||||
result = new HashSet<>();
|
||||
Set<MetaLanguage> result = new HashSet<>();
|
||||
MetaLanguage.EP_NAME.forEachExtensionSafe(metaLanguage -> {
|
||||
if (metaLanguage.matchesLanguage(language)) {
|
||||
result.add(metaLanguage);
|
||||
}
|
||||
});
|
||||
toCache = result.isEmpty() ? Collections.emptySet() : ContainerUtil.immutableList(result.toArray(new MetaLanguage[0]));
|
||||
}
|
||||
Pair<SoftReference<Application>, Set<MetaLanguage>> toCache =
|
||||
Pair.create(new SoftReference<>(ApplicationManager.getApplication()), result);
|
||||
language.putUserData(MATCHING_LANGUAGES, toCache);
|
||||
return result;
|
||||
language.putUserData(MATCHING_META_LANGUAGES, toCache);
|
||||
return toCache;
|
||||
}
|
||||
|
||||
static void clearMatchingMetaLanguages(@NotNull Language language) {
|
||||
language.putUserData(MATCHING_LANGUAGES, null);
|
||||
static void clearMatchingMetaLanguagesCache(@NotNull Language language) {
|
||||
language.putUserData(MATCHING_META_LANGUAGES, null);
|
||||
}
|
||||
|
||||
public static @NotNull JBIterable<Language> getBaseLanguages(@NotNull Language language) {
|
||||
@@ -202,7 +198,6 @@ public final class LanguageUtil {
|
||||
final Language language = Language.findLanguageByID(langValueText);
|
||||
if (language != null) return language;
|
||||
|
||||
return ContainerUtil.find(Language.getRegisteredLanguages(),
|
||||
e -> e.getID().equalsIgnoreCase(langValueText));
|
||||
return ContainerUtil.find(Language.getRegisteredLanguages(), e -> e.getID().equalsIgnoreCase(langValueText));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.openapi.extensions.ExtensionPointListener;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -25,7 +26,7 @@ public abstract class MetaLanguage extends Language {
|
||||
public void extensionRemoved(@NotNull MetaLanguage metaLanguage, @NotNull PluginDescriptor pluginDescriptor) {
|
||||
if (MetaLanguage.this == metaLanguage) {
|
||||
for (Language matchingLanguage : metaLanguage.getMatchingLanguages()) {
|
||||
LanguageUtil.clearMatchingMetaLanguages(matchingLanguage);
|
||||
LanguageUtil.clearMatchingMetaLanguagesCache(matchingLanguage);
|
||||
}
|
||||
metaLanguage.unregisterLanguage(pluginDescriptor);
|
||||
}
|
||||
@@ -48,4 +49,11 @@ public abstract class MetaLanguage extends Language {
|
||||
public @NotNull Collection<Language> getMatchingLanguages() {
|
||||
return ContainerUtil.filter(Language.getRegisteredLanguages(), language -> matchesLanguage(language));
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void clearAllMatchingMetaLanguagesCache() {
|
||||
for (Language language : Language.getRegisteredLanguages()) {
|
||||
LanguageUtil.clearMatchingMetaLanguagesCache(language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.mock;
|
||||
|
||||
import com.intellij.lang.MetaLanguage;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.application.ex.ApplicationEx;
|
||||
@@ -382,4 +383,12 @@ public class MockApplication extends MockComponentManager implements Application
|
||||
@Override
|
||||
public void setSaveAllowed(boolean value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// A mock application may cause incorrect caching during tests. It does not fire extension point removed events.
|
||||
// Ensure that we have cached against correct application.
|
||||
MetaLanguage.clearAllMatchingMetaLanguagesCache();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user