[lombok] IDEA-264579 added cache to prevent multiple file index access for same keys

GitOrigin-RevId: c8a5b1da548f57f3a2bb98a1a163a3e0ca79eb74
This commit is contained in:
Michail Plushnikov
2021-03-24 16:18:35 +01:00
committed by intellij-monorepo-bot
parent cbfd2f4ad9
commit 20d81fdd6c
7 changed files with 103 additions and 89 deletions

View File

@@ -11,7 +11,7 @@ import de.plushnikov.intellij.plugin.lombokconfig.ConfigKey;
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
/**
@@ -48,10 +48,10 @@ public class SpringQualifierCopyableLombokAnnotationInspection extends LombokJav
if (psiClass != null && PsiAnnotationSearchUtil.isAnnotatedWith(psiClass,
LombokClassNames.REQUIRED_ARGS_CONSTRUCTOR,
LombokClassNames.ALL_ARGS_CONSTRUCTOR)) {
String[] configuredCopyableAnnotations =
Collection<String> configuredCopyableAnnotations =
ConfigDiscovery.getInstance().getMultipleValueLombokConfigProperty(ConfigKey.COPYABLE_ANNOTATIONS, psiClass);
if (!Arrays.asList(configuredCopyableAnnotations).contains(SPRING_QUALIFIER_FQN)) {
if (!configuredCopyableAnnotations.contains(SPRING_QUALIFIER_FQN)) {
holder.registerProblem(annotation,
LombokBundle.message("inspection.message.annotation.not.lombok.copyable",
SPRING_QUALIFIER_FQN),

View File

@@ -9,9 +9,10 @@ import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScopes;
import com.intellij.util.ArrayUtil;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.indexing.FileBasedIndex;
import de.plushnikov.intellij.plugin.psi.LombokLightClassBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -25,12 +26,11 @@ public class ConfigDiscovery {
@NotNull
public String getStringLombokConfigProperty(@NotNull ConfigKey configKey, @NotNull PsiClass psiClass) {
@Nullable VirtualFile file = calculateDirectory(psiClass);
if (null != file) {
return discoverProperty(configKey, file, psiClass.getProject());
} else {
return configKey.getConfigDefaultValue();
@Nullable PsiFile psiFile = calculatePsiFile(psiClass);
if (null != psiFile) {
return discoverPropertyWithCache(configKey, psiFile);
}
return configKey.getConfigDefaultValue();
}
public boolean getBooleanLombokConfigProperty(@NotNull ConfigKey configKey, @NotNull PsiClass psiClass) {
@@ -38,67 +38,44 @@ public class ConfigDiscovery {
return Boolean.parseBoolean(configProperty);
}
public String @NotNull [] getMultipleValueLombokConfigProperty(@NotNull ConfigKey configKey, @NotNull PsiClass psiClass) {
final Collection<String> result = new HashSet<>();
@Nullable VirtualFile file = calculateDirectory(psiClass);
if (file != null) {
final List<String> properties = discoverProperties(configKey, file, psiClass.getProject());
Collections.reverse(properties);
for (String configProperty : properties) {
if (StringUtil.isNotEmpty(configProperty)) {
final String[] values = configProperty.split(";");
for (String value : values) {
if (value.startsWith("+")) {
result.add(value.substring(1));
} else if (value.startsWith("-")) {
result.remove(value.substring(1));
}
}
}
}
} else {
result.add(configKey.getConfigDefaultValue());
public @NotNull Collection<String> getMultipleValueLombokConfigProperty(@NotNull ConfigKey configKey, @NotNull PsiClass psiClass) {
@Nullable PsiFile psiFile = calculatePsiFile(psiClass);
if (psiFile != null) {
return discoverPropertiesWithCache(configKey, psiFile);
}
return ArrayUtil.toStringArray(result);
return Collections.singletonList(configKey.getConfigDefaultValue());
}
@Nullable
private static VirtualFile calculateDirectory(@NotNull PsiClass psiClass) {
PsiFile psiFile;
if (psiClass instanceof LombokLightClassBuilder) {
// Use containing class for all LombokLightClasses
final PsiClass containingClass = psiClass.getContainingClass();
if (null != containingClass) {
psiFile = containingClass.getContainingFile();
} else {
psiFile = null;
}
} else {
psiFile = psiClass.getContainingFile();
}
private static PsiFile calculatePsiFile(@NotNull PsiClass psiClass) {
PsiFile psiFile = psiClass.getContainingFile();
if (psiFile != null) {
PsiFile originalFile = psiFile.getOriginalFile();
if (originalFile != null) {
psiFile = originalFile;
}
psiFile = psiFile.getOriginalFile();
}
return psiFile != null ? psiFile.getVirtualFile() : null;
return psiFile;
}
@NotNull
private String discoverProperty(@NotNull ConfigKey configKey, @Nullable VirtualFile file, @NotNull Project project) {
@Nullable VirtualFile currentFile = file;
protected String discoverPropertyWithCache(@NotNull ConfigKey configKey, @NotNull PsiFile psiFile) {
return CachedValuesManager.getCachedValue(psiFile, () -> {
Map<ConfigKey, String> result =
ConcurrentFactoryMap.createMap(configKeyInner -> discoverProperty(configKeyInner, psiFile));
return CachedValueProvider.Result.create(result, LombokConfigIndex.CONFIG_CHANGE_TRACKER);
}).get(configKey);
}
@NotNull
protected String discoverProperty(@NotNull ConfigKey configKey, @NotNull PsiFile psiFile) {
@Nullable VirtualFile currentFile = psiFile.getVirtualFile();
while (currentFile != null) {
ConfigValue configValue = readProperty(configKey, project, currentFile);
ConfigValue configValue = readProperty(configKey, psiFile.getProject(), currentFile);
if (null != configValue) {
if (null == configValue.getValue()) {
if (configValue.isStopBubbling()) {
break;
}
} else {
}
else {
return configValue.getValue();
}
}
@@ -125,25 +102,52 @@ public class ConfigDiscovery {
}
@NotNull
private List<String> discoverProperties(@NotNull ConfigKey configKey, @Nullable VirtualFile file, @NotNull Project project) {
List<String> result = new ArrayList<>();
protected Collection<String> discoverPropertiesWithCache(@NotNull ConfigKey configKey, @NotNull PsiFile psiFile) {
return CachedValuesManager.getCachedValue(psiFile, () -> {
Map<ConfigKey, Collection<String>> result = ConcurrentFactoryMap.createMap(configKeyInner -> discoverProperties(configKeyInner, psiFile));
return CachedValueProvider.Result.create(result, LombokConfigIndex.CONFIG_CHANGE_TRACKER);
}).get(configKey);
}
@Nullable VirtualFile currentFile = file;
@NotNull
protected Collection<String> discoverProperties(@NotNull ConfigKey configKey, @NotNull PsiFile file) {
List<String> properties = new ArrayList<>();
@Nullable VirtualFile currentFile = file.getVirtualFile();
while (currentFile != null) {
final ConfigValue configValue = readProperty(configKey, project, currentFile);
final ConfigValue configValue = readProperty(configKey, file.getProject(), currentFile);
if (null != configValue) {
if (null == configValue.getValue()) {
if (configValue.isStopBubbling()) {
break;
}
} else {
result.add(configValue.getValue());
}
else {
properties.add(configValue.getValue());
}
}
currentFile = currentFile.getParent();
}
Collections.reverse(properties);
Set<String> result = new HashSet<>();
for (String configProperty : properties) {
if (StringUtil.isNotEmpty(configProperty)) {
final String[] values = configProperty.split(";");
for (String value : values) {
if (value.startsWith("+")) {
result.add(value.substring(1));
}
else if (value.startsWith("-")) {
result.remove(value.substring(1));
}
}
}
}
return result;
}
}

View File

@@ -1,5 +1,7 @@
package de.plushnikov.intellij.plugin.lombokconfig;
import java.util.Locale;
public enum ConfigKey {
CONFIG_STOP_BUBBLING("config.stopBubbling", "false"),
@@ -89,7 +91,7 @@ public enum ConfigKey {
private final String configDefaultValue;
ConfigKey(String configKey, String configDefaultValue) {
this.configKey = configKey.toLowerCase();
this.configKey = configKey.toLowerCase(Locale.ENGLISH);
this.configDefaultValue = configDefaultValue;
}

View File

@@ -1,5 +1,6 @@
package de.plushnikov.intellij.plugin.lombokconfig;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -24,8 +25,12 @@ import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
public class LombokConfigIndex extends FileBasedIndexExtension<ConfigKey, ConfigValue> {
private static final AtomicLong configChangeCount = new AtomicLong(1);
public static final ModificationTracker CONFIG_CHANGE_TRACKER = configChangeCount::get;
@NonNls
public static final ID<ConfigKey, ConfigValue> NAME = ID.create("LombokConfigIndex");
@@ -56,7 +61,7 @@ public class LombokConfigIndex extends FileBasedIndexExtension<ConfigKey, Config
new ConfigValue(configValues.get(key.getConfigKey()), stopBubblingValue)));
}
}
configChangeCount.incrementAndGet();
return result;
}

View File

@@ -15,7 +15,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -103,9 +102,9 @@ public abstract class AbstractProcessor implements Processor {
final PsiClass containingClass = psiField.getContainingClass();
// append only for BASE_COPYABLE
if (copyableAnnotations == LombokUtils.BASE_COPYABLE_ANNOTATIONS && null != containingClass) {
String[] configuredCopyableAnnotations =
Collection<String> configuredCopyableAnnotations =
ConfigDiscovery.getInstance().getMultipleValueLombokConfigProperty(ConfigKey.COPYABLE_ANNOTATIONS, containingClass);
combinedListOfCopyableAnnotations.addAll(Arrays.asList(configuredCopyableAnnotations));
combinedListOfCopyableAnnotations.addAll(configuredCopyableAnnotations);
}
final List<String> existingAnnotations = ContainerUtil.map(psiField.getAnnotations(), PsiAnnotation::getQualifiedName);

View File

@@ -4,6 +4,7 @@ import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiVariable;
import com.intellij.util.ArrayUtil;
import de.plushnikov.intellij.plugin.LombokClassNames;
import de.plushnikov.intellij.plugin.lombokconfig.ConfigDiscovery;
import de.plushnikov.intellij.plugin.lombokconfig.ConfigKey;
@@ -30,7 +31,7 @@ public class AccessorsInfo {
this.fluent = fluentValue;
this.chain = chainValue;
this.doNotUseIsPrefix = doNotUseIsPrefix;
this.prefixes = null == prefixes ? new String[0] : prefixes;
this.prefixes = null == prefixes ? ArrayUtil.EMPTY_STRING_ARRAY : prefixes;
}
@NotNull
@@ -109,9 +110,9 @@ public class AccessorsInfo {
}
if (prefixDeclared.isEmpty()) {
prefixes = configDiscovery.getMultipleValueLombokConfigProperty(ConfigKey.ACCESSORS_PREFIX, psiClass);
prefixes = ArrayUtil.toStringArray(configDiscovery.getMultipleValueLombokConfigProperty(ConfigKey.ACCESSORS_PREFIX, psiClass));
} else {
prefixes = prefixDeclared.toArray(new String[0]);
prefixes = ArrayUtil.toStringArray(prefixDeclared);
}
doNotUseIsPrefix = configDiscovery.getBooleanLombokConfigProperty(ConfigKey.GETTER_NO_IS_PREFIX, psiClass);
@@ -119,7 +120,7 @@ public class AccessorsInfo {
} else {
isFluent = null != fluentDeclaredValue && fluentDeclaredValue;
isChained = null != chainDeclaredValue && chainDeclaredValue;
prefixes = prefixDeclared.toArray(new String[0]);
prefixes = ArrayUtil.toStringArray(prefixDeclared);
doNotUseIsPrefix = false;
}

View File

@@ -13,14 +13,12 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;
@@ -58,10 +56,23 @@ public class ConfigDiscoveryTest {
protected FileBasedIndex getFileBasedIndex() {
return fileBasedIndex;
}
@Override
protected @NotNull String discoverPropertyWithCache(@NotNull ConfigKey configKey,
@NotNull PsiFile psiFile) {
return super.discoverProperty(configKey, psiFile);
}
@Override
protected @NotNull Collection<String> discoverPropertiesWithCache(@NotNull ConfigKey configKey,
@NotNull PsiFile psiFile) {
return super.discoverProperties(configKey, psiFile);
}
};
when(psiClass.getProject()).thenReturn(project);
when(psiFile.getProject()).thenReturn(project);
when(psiClass.getContainingFile()).thenReturn(psiFile);
when(psiFile.getOriginalFile()).thenReturn(psiFile);
when(psiFile.getVirtualFile()).thenReturn(virtualFile);
when(virtualFile.getParent()).thenReturn(parentVirtualFile);
when(parentVirtualFile.getParent()).thenReturn(parentParVirtualFile);
@@ -113,13 +124,8 @@ public class ConfigDiscoveryTest {
when(fileBasedIndex.getValues(eq(LombokConfigIndex.NAME), eq(configKey), any(GlobalSearchScope.class)))
.thenReturn(makeValue("+_d;"), Collections.emptyList(), makeValue("-a;+cc"), makeValue("+a;+b"));
final String[] properties = discovery.getMultipleValueLombokConfigProperty(configKey, psiClass);
assertNotNull(properties);
assertEquals(3, properties.length);
final ArrayList<String> list = new ArrayList<>(Arrays.asList(properties));
assertTrue(list.contains("b"));
assertTrue(list.contains("cc"));
assertTrue(list.contains("_d"));
final Collection<String> properties = discovery.getMultipleValueLombokConfigProperty(configKey, psiClass);
assertThat(properties, hasItems("b", "cc", "_d"));
}
@NotNull
@@ -133,10 +139,7 @@ public class ConfigDiscoveryTest {
when(fileBasedIndex.getValues(eq(LombokConfigIndex.NAME), eq(configKey), isA(GlobalSearchScope.class)))
.thenReturn(makeValue("+_d;"));
final String[] properties = discovery.getMultipleValueLombokConfigProperty(configKey, psiClass);
assertNotNull(properties);
assertEquals(1, properties.length);
final ArrayList<String> list = new ArrayList<>(Arrays.asList(properties));
assertTrue(list.contains("_d"));
final Collection<String> properties = discovery.getMultipleValueLombokConfigProperty(configKey, psiClass);
assertThat(properties, hasItems("_d"));
}
}