[java-lombok] IDEA-352726 Augment class in dumb mode in Lombok

- support dumb mode

GitOrigin-RevId: 93a6325ee1fa6ef515c579aa09bec9eb290ed967
This commit is contained in:
Mikhail Pyltsin
2024-05-10 17:36:19 +02:00
committed by intellij-monorepo-bot
parent b88da56f34
commit 2ca5b2bcd4
32 changed files with 461 additions and 100 deletions

View File

@@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.*; import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.registry.Registry;
@@ -347,8 +348,19 @@ public final class PsiClassImplUtil {
private final ConcurrentMap<MemberType, PsiMember[]> myAllMembers; private final ConcurrentMap<MemberType, PsiMember[]> myAllMembers;
MemberCache(@NotNull PsiClass psiClass, @NotNull GlobalSearchScope scope) { MemberCache(@NotNull PsiClass psiClass, @NotNull GlobalSearchScope scope) {
boolean dumb = DumbService.isDumb(psiClass.getProject());
myAllSupers = JBTreeTraverser myAllSupers = JBTreeTraverser
.from((PsiClass c) -> ContainerUtil.mapNotNull(c.getSupers(), s -> PsiSuperMethodUtil.correctClassByScope(s, scope))) .from((PsiClass c) -> ContainerUtil.mapNotNull(c.getSupers(),
superOne -> {
PsiClass correctedClass = PsiSuperMethodUtil.correctClassByScope(superOne, scope);
if (correctedClass == null && dumb) {
if (superOne.getContainingFile() instanceof PsiJavaFile &&
((PsiJavaFile)superOne.getContainingFile()).getPackageStatement() == null) {
return superOne;
}
}
return correctedClass;
}))
.unique() .unique()
.withRoot(psiClass) .withRoot(psiClass)
.toList(); .toList();

View File

@@ -75,8 +75,9 @@ public final class SneakyThrowsExceptionHandler extends CustomExceptionHandler {
return false; return false;
} }
List<PsiType> throwable = List.of(PsiType.getJavaLangThrowable(psiAnnotation.getManager(), psiAnnotation.getResolveScope()));
final Collection<PsiType> sneakedExceptionTypes = final Collection<PsiType> sneakedExceptionTypes =
PsiAnnotationUtil.getAnnotationValues(psiAnnotation, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME, PsiType.class); PsiAnnotationUtil.getAnnotationValues(psiAnnotation, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME, PsiType.class, throwable);
//Default SneakyThrows handles all exceptions //Default SneakyThrows handles all exceptions
return sneakedExceptionTypes.isEmpty() return sneakedExceptionTypes.isEmpty()
|| sneakedExceptionTypes.iterator().next().equalsToText(JAVA_LANG_THROWABLE) || sneakedExceptionTypes.iterator().next().equalsToText(JAVA_LANG_THROWABLE)

View File

@@ -1,7 +1,9 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package de.plushnikov.intellij.plugin.inspection; package de.plushnikov.intellij.plugin.inspection;
import com.intellij.codeInspection.*; import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.modcommand.ModPsiUpdater; import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix; import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
@@ -13,6 +15,7 @@ import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.javadoc.PsiDocToken;
import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.CommentTracker;
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -21,7 +24,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJavaInspectionBase { public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJavaInspectionBase {
@@ -58,7 +60,7 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava
} }
boolean isLombokAnnotationAtClassLevel = true; boolean isLombokAnnotationAtClassLevel = true;
for (PsiField field : psiClass.getFields()) { for (PsiField field : psiClass.getFields()) {
PsiAnnotation annotation = field.getAnnotation(getAnnotationName()); PsiAnnotation annotation = PsiAnnotationSearchUtil.findAnnotation(field, getAnnotationName());
if (annotation != null) { if (annotation != null) {
if (!annotation.getAttributes().isEmpty() || field.hasModifierProperty(PsiModifier.STATIC)) { if (!annotation.getAttributes().isEmpty() || field.hasModifierProperty(PsiModifier.STATIC)) {
isLombokAnnotationAtClassLevel = false; isLombokAnnotationAtClassLevel = false;
@@ -183,7 +185,7 @@ public abstract class LombokGetterOrSetterMayBeUsedInspection extends LombokJava
removeMethodAndMoveJavaDoc(field, method); removeMethodAndMoveJavaDoc(field, method);
} }
for (PsiField annotatedField : annotatedFields) { for (PsiField annotatedField : annotatedFields) {
PsiAnnotation oldAnnotation = annotatedField.getAnnotation(getAnnotationName()); PsiAnnotation oldAnnotation = PsiAnnotationSearchUtil.findAnnotation(annotatedField, getAnnotationName());
if (oldAnnotation != null) { if (oldAnnotation != null) {
new CommentTracker().deleteAndRestoreComments(oldAnnotation); new CommentTracker().deleteAndRestoreComments(oldAnnotation);
} }

View File

@@ -1,14 +1,10 @@
package de.plushnikov.intellij.plugin.inspection; package de.plushnikov.intellij.plugin.inspection;
import com.intellij.codeInsight.daemon.impl.quickfix.SafeDeleteFix;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.RemoveAnnotationQuickFix; import com.intellij.codeInspection.RemoveAnnotationQuickFix;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteAnnotation;
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverrideAnnotation;
import com.intellij.util.JavaPsiConstructorUtil; import com.intellij.util.JavaPsiConstructorUtil;
import de.plushnikov.intellij.plugin.LombokBundle; import de.plushnikov.intellij.plugin.LombokBundle;
import de.plushnikov.intellij.plugin.LombokClassNames; import de.plushnikov.intellij.plugin.LombokClassNames;
@@ -19,6 +15,7 @@ import de.plushnikov.intellij.plugin.processor.Processor;
import de.plushnikov.intellij.plugin.processor.ValProcessor; import de.plushnikov.intellij.plugin.processor.ValProcessor;
import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder; import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder;
import de.plushnikov.intellij.plugin.quickfix.PsiQuickFixFactory; import de.plushnikov.intellij.plugin.quickfix.PsiQuickFixFactory;
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
@@ -86,8 +83,8 @@ public final class LombokInspection extends LombokJavaInspectionBase {
if (annotation.hasQualifiedName(LombokClassNames.BUILDER_DEFAULT)) { if (annotation.hasQualifiedName(LombokClassNames.BUILDER_DEFAULT)) {
final PsiClass parentOfAnnotation = PsiTreeUtil.getParentOfType(annotation, PsiClass.class); final PsiClass parentOfAnnotation = PsiTreeUtil.getParentOfType(annotation, PsiClass.class);
if (null != parentOfAnnotation) { if (null != parentOfAnnotation) {
if (!parentOfAnnotation.hasAnnotation(LombokClassNames.BUILDER) && if (!PsiAnnotationSearchUtil.isAnnotatedWith(parentOfAnnotation, LombokClassNames.BUILDER) &&
!parentOfAnnotation.hasAnnotation(LombokClassNames.SUPER_BUILDER)) { !PsiAnnotationSearchUtil.isAnnotatedWith(parentOfAnnotation, LombokClassNames.SUPER_BUILDER)) {
final LombokProblemInstance problemInstance = new LombokProblemInstance( final LombokProblemInstance problemInstance = new LombokProblemInstance(
LombokBundle.message("inspection.message.builder.default.requires.builder.annotation"), ProblemHighlightType.GENERIC_ERROR); LombokBundle.message("inspection.message.builder.default.requires.builder.annotation"), ProblemHighlightType.GENERIC_ERROR);
problemInstance.withLocalQuickFixes( problemInstance.withLocalQuickFixes(

View File

@@ -1,11 +1,11 @@
package de.plushnikov.intellij.plugin.inspection.modifiers; package de.plushnikov.intellij.plugin.inspection.modifiers;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.ig.fixes.RemoveModifierFix; import com.siyeh.ig.fixes.RemoveModifierFix;
import de.plushnikov.intellij.plugin.inspection.LombokJavaInspectionBase; import de.plushnikov.intellij.plugin.inspection.LombokJavaInspectionBase;
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -82,8 +82,8 @@ public abstract class LombokRedundantModifierInspection extends LombokJavaInspec
|| (infoType != RedundantModifiersInfoType.VARIABLE && !(parentModifierListOwner instanceof PsiClass))) { || (infoType != RedundantModifiersInfoType.VARIABLE && !(parentModifierListOwner instanceof PsiClass))) {
continue; continue;
} }
if ((supportedAnnotation == null || parentModifierListOwner.hasAnnotation(supportedAnnotation)) && if ((supportedAnnotation == null || PsiAnnotationSearchUtil.isAnnotatedWith(parentModifierListOwner, supportedAnnotation)) &&
redundantModifiersInfo.getType().getSupportedClass().isAssignableFrom(psiModifierListOwner.getClass())) { redundantModifiersInfo.getType().getSupportedClass().isAssignableFrom(psiModifierListOwner.getClass())) {
PsiModifierList psiModifierList = psiModifierListOwner.getModifierList(); PsiModifierList psiModifierList = psiModifierListOwner.getModifierList();
if (psiModifierList == null || if (psiModifierList == null ||
(redundantModifiersInfo.getDontRunOnModifier() != null && psiModifierList.hasExplicitModifier(redundantModifiersInfo.getDontRunOnModifier()))) { (redundantModifiersInfo.getDontRunOnModifier() != null && psiModifierList.hasExplicitModifier(redundantModifiersInfo.getDontRunOnModifier()))) {

View File

@@ -2,6 +2,7 @@ package de.plushnikov.intellij.plugin.lombokconfig;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
@@ -124,6 +125,9 @@ public class ConfigDiscovery {
@Nullable @Nullable
private ConfigValue readProperty(@NotNull ConfigKey configKey, @NotNull Project project, @NotNull VirtualFile directory) { private ConfigValue readProperty(@NotNull ConfigKey configKey, @NotNull Project project, @NotNull VirtualFile directory) {
if (DumbService.getInstance(project).isAlternativeResolveEnabled()) {
return LombokConfigIndex.readPropertyWithAlternativeResolver(configKey, project, directory);
}
GlobalSearchScope directoryScope = GlobalSearchScopes.directoryScope(project, directory, false); GlobalSearchScope directoryScope = GlobalSearchScopes.directoryScope(project, directory, false);
List<ConfigValue> values = getFileBasedIndex().getValues(LombokConfigIndex.NAME, configKey, directoryScope); List<ConfigValue> values = getFileBasedIndex().getValues(LombokConfigIndex.NAME, configKey, directoryScope);
if (!values.isEmpty()) { if (!values.isEmpty()) {

View File

@@ -1,8 +1,15 @@
package de.plushnikov.intellij.plugin.lombokconfig; package de.plushnikov.intellij.plugin.lombokconfig;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.PathUtil; import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.*; import com.intellij.util.indexing.*;
@@ -16,6 +23,7 @@ import de.plushnikov.intellij.plugin.language.psi.LombokConfigFile;
import de.plushnikov.intellij.plugin.language.psi.LombokConfigProperty; import de.plushnikov.intellij.plugin.language.psi.LombokConfigProperty;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
@@ -25,6 +33,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public final class LombokConfigIndex extends FileBasedIndexExtension<ConfigKey, ConfigValue> { public final class LombokConfigIndex extends FileBasedIndexExtension<ConfigKey, ConfigValue> {
@NotNull
private static final String LOMBOK_CONFIG_FILE_NAME = "lombok.config";
@NonNls @NonNls
public static final ID<ConfigKey, ConfigValue> NAME = ID.create("LombokConfigIndex"); public static final ID<ConfigKey, ConfigValue> NAME = ID.create("LombokConfigIndex");
@@ -41,56 +51,64 @@ public final class LombokConfigIndex extends FileBasedIndexExtension<ConfigKey,
@NotNull @NotNull
@Override @Override
public Map<ConfigKey, ConfigValue> map(@NotNull FileContent inputData) { public Map<ConfigKey, ConfigValue> map(@NotNull FileContent inputData) {
Map<ConfigKey, ConfigValue> result = Collections.emptyMap();
final VirtualFile directoryFile = inputData.getFile().getParent(); final VirtualFile directoryFile = inputData.getFile().getParent();
if (null != directoryFile) { if (null != directoryFile) {
final String canonicalPath = PathUtil.toSystemIndependentName(directoryFile.getCanonicalPath()); final String canonicalPath = PathUtil.toSystemIndependentName(directoryFile.getCanonicalPath());
if (null != canonicalPath) { if (null != canonicalPath) {
final Map<String, String> configValues = extractValues((LombokConfigFile)inputData.getPsiFile()); PsiFile psiFile = inputData.getPsiFile();
return createConfigMapResult(psiFile);
final boolean stopBubblingValue = Boolean.parseBoolean(configValues.get(StringUtil.toLowerCase(ConfigKey.CONFIG_STOP_BUBBLING.getConfigKey())));
result = ContainerUtil.map2Map(ConfigKey.values(),
key -> Pair.create(key,
new ConfigValue(configValues.get(StringUtil.toLowerCase(key.getConfigKey())), stopBubblingValue)));
} }
} }
return result; return Collections.emptyMap();
}
private static Map<String, String> extractValues(LombokConfigFile configFile) {
Map<String, String> result = new HashMap<>();
final LombokConfigCleaner[] configCleaners = LombokConfigUtil.getLombokConfigCleaners(configFile);
for (LombokConfigCleaner configCleaner : configCleaners) {
final String key = StringUtil.toLowerCase(configCleaner.getKey());
final ConfigKey configKey = ConfigKey.fromConfigStringKey(key);
if (null != configKey) {
result.put(key, configKey.getConfigDefaultValue());
}
}
final LombokConfigProperty[] configProperties = LombokConfigUtil.getLombokConfigProperties(configFile);
for (LombokConfigProperty configProperty : configProperties) {
final String key = StringUtil.toLowerCase(configProperty.getKey());
final String value = configProperty.getValue();
final String sign = configProperty.getSign();
if (null == sign) {
result.put(key, value);
}
else {
final String previousValue = StringUtil.defaultIfEmpty(result.get(key), "");
final String combinedValue = previousValue + sign + value + ";";
result.put(key, combinedValue);
}
}
return result;
} }
}; };
} }
private static @NotNull Map<ConfigKey, ConfigValue> createConfigMapResult(@Nullable PsiFile psiFile) {
if (!(psiFile instanceof LombokConfigFile)) {
return Map.of();
}
final Map<String, String> configValues = extractValues((LombokConfigFile)psiFile);
final boolean stopBubblingValue =
Boolean.parseBoolean(configValues.get(StringUtil.toLowerCase(ConfigKey.CONFIG_STOP_BUBBLING.getConfigKey())));
return ContainerUtil.map2Map(ConfigKey.values(),
key -> Pair.create(key,
new ConfigValue(configValues.get(StringUtil.toLowerCase(key.getConfigKey())),
stopBubblingValue)));
}
private static Map<String, String> extractValues(LombokConfigFile configFile) {
Map<String, String> result = new HashMap<>();
final LombokConfigCleaner[] configCleaners = LombokConfigUtil.getLombokConfigCleaners(configFile);
for (LombokConfigCleaner configCleaner : configCleaners) {
final String key = StringUtil.toLowerCase(configCleaner.getKey());
final ConfigKey configKey = ConfigKey.fromConfigStringKey(key);
if (null != configKey) {
result.put(key, configKey.getConfigDefaultValue());
}
}
final LombokConfigProperty[] configProperties = LombokConfigUtil.getLombokConfigProperties(configFile);
for (LombokConfigProperty configProperty : configProperties) {
final String key = StringUtil.toLowerCase(configProperty.getKey());
final String value = configProperty.getValue();
final String sign = configProperty.getSign();
if (null == sign) {
result.put(key, value);
}
else {
final String previousValue = StringUtil.defaultIfEmpty(result.get(key), "");
final String combinedValue = previousValue + sign + value + ";";
result.put(key, combinedValue);
}
}
return result;
}
@NotNull @NotNull
@Override @Override
public KeyDescriptor<ConfigKey> getKeyDescriptor() { public KeyDescriptor<ConfigKey> getKeyDescriptor() {
@@ -134,4 +152,27 @@ public final class LombokConfigIndex extends FileBasedIndexExtension<ConfigKey,
public int getVersion() { public int getVersion() {
return 14; return 14;
} }
static @Nullable ConfigValue readPropertyWithAlternativeResolver(@NotNull ConfigKey key,
@NotNull Project project,
@NotNull VirtualFile directory) {
VirtualFile configVirtualFile = directory.findFileByRelativePath(LOMBOK_CONFIG_FILE_NAME);
if (configVirtualFile == null) {
return null;
}
Document document = FileDocumentManager.getInstance().getDocument(configVirtualFile);
if (document == null) {
return null;
}
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (psiFile == null) {
return null;
}
Map<ConfigKey, ConfigValue> values = CachedValuesManager.getCachedValue(psiFile, () -> {
Map<ConfigKey, ConfigValue> result = createConfigMapResult(psiFile);
//CONFIG_CHANGE_TRACKER is not really accurate, but it is already used for this purpose
return CachedValueProvider.Result.create(result, LombokConfigChangeListener.CONFIG_CHANGE_TRACKER);
});
return values.get(key);
}
} }

View File

@@ -62,8 +62,8 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor {
} }
if (problemSink.deepValidation()) { if (problemSink.deepValidation()) {
final Collection<String> excludeProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class); final Collection<String> excludeProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class, List.of());
final Collection<String> ofProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class); final Collection<String> ofProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class, List.of());
if (!excludeProperty.isEmpty() && !ofProperty.isEmpty()) { if (!excludeProperty.isEmpty() && !ofProperty.isEmpty()) {
problemSink.addWarningMessage("inspection.message.exclude.are.mutually.exclusive.exclude.parameter.will.be.ignored") problemSink.addWarningMessage("inspection.message.exclude.are.mutually.exclusive.exclude.parameter.will.be.ignored")

View File

@@ -55,8 +55,8 @@ public final class ToStringProcessor extends AbstractClassProcessor {
} }
if (problemSink.deepValidation()) { if (problemSink.deepValidation()) {
final Collection<String> excludeProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class); final Collection<String> excludeProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class, List.of());
final Collection<String> ofProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class); final Collection<String> ofProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class, List.of());
if (!excludeProperty.isEmpty() && !ofProperty.isEmpty()) { if (!excludeProperty.isEmpty() && !ofProperty.isEmpty()) {
problemSink.addWarningMessage("inspection.message.exclude.are.mutually.exclusive.exclude.parameter.will.be.ignored") problemSink.addWarningMessage("inspection.message.exclude.are.mutually.exclusive.exclude.parameter.will.be.ignored")

View File

@@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
/** /**
* @author Plushnikov Michail * @author Plushnikov Michail
@@ -148,7 +149,7 @@ public class AccessorsInfo {
Boolean chainDeclaredValue = PsiAnnotationUtil.getDeclaredBooleanAnnotationValue(accessorsAnnotation, CHAIN_VALUE); Boolean chainDeclaredValue = PsiAnnotationUtil.getDeclaredBooleanAnnotationValue(accessorsAnnotation, CHAIN_VALUE);
Boolean fluentDeclaredValue = PsiAnnotationUtil.getDeclaredBooleanAnnotationValue(accessorsAnnotation, FLUENT_VALUE); Boolean fluentDeclaredValue = PsiAnnotationUtil.getDeclaredBooleanAnnotationValue(accessorsAnnotation, FLUENT_VALUE);
Boolean makeFinalDeclaredValue = PsiAnnotationUtil.getDeclaredBooleanAnnotationValue(accessorsAnnotation, MAKE_FINAL_VALUE); Boolean makeFinalDeclaredValue = PsiAnnotationUtil.getDeclaredBooleanAnnotationValue(accessorsAnnotation, MAKE_FINAL_VALUE);
Collection<String> prefixes = PsiAnnotationUtil.getAnnotationValues(accessorsAnnotation, PREFIX_VALUE, String.class); Collection<String> prefixes = PsiAnnotationUtil.getAnnotationValues(accessorsAnnotation, PREFIX_VALUE, String.class, List.of());
return new AccessorsValues(chainDeclaredValue, fluentDeclaredValue, makeFinalDeclaredValue, prefixes); return new AccessorsValues(chainDeclaredValue, fluentDeclaredValue, makeFinalDeclaredValue, prefixes);
} }

View File

@@ -75,7 +75,7 @@ public class BuilderHandler {
public static Map<String, List<List<PsiType>>> getExistingMethodsWithParameterTypes(@NotNull PsiClass psiClass) { public static Map<String, List<List<PsiType>>> getExistingMethodsWithParameterTypes(@NotNull PsiClass psiClass) {
return PsiClassUtil.collectClassMethodsIntern(psiClass).stream() return PsiClassUtil.collectClassMethodsIntern(psiClass).stream()
.filter(psiMethod -> !psiMethod.hasAnnotation(LombokClassNames.TOLERATE)) .filter(psiMethod -> !PsiAnnotationSearchUtil.isAnnotatedWith(psiMethod, LombokClassNames.TOLERATE))
.collect(Collectors.groupingBy(PsiMethod::getName, .collect(Collectors.groupingBy(PsiMethod::getName,
Collectors.mapping(BuilderHandler::getMethodParameterTypes, Collectors.toList()))); Collectors.mapping(BuilderHandler::getMethodParameterTypes, Collectors.toList())));
} }

View File

@@ -63,8 +63,8 @@ public class BuilderInfo {
result.capitalizationStrategy = CapitalizationStrategy.defaultValue(); result.capitalizationStrategy = CapitalizationStrategy.defaultValue();
result.deprecated = PsiImplUtil.isDeprecated(psiVariable); result.deprecated = PsiImplUtil.isDeprecated(psiVariable);
result.hasBuilderDefaultAnnotation = psiVariable.hasAnnotation(BUILDER_DEFAULT_ANNOTATION); result.hasBuilderDefaultAnnotation = PsiAnnotationSearchUtil.isAnnotatedWith(psiVariable, BUILDER_DEFAULT_ANNOTATION);
result.singularAnnotation = psiVariable.getAnnotation(LombokClassNames.SINGULAR); result.singularAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiVariable, LombokClassNames.SINGULAR);
result.builderElementHandler = SingularHandlerFactory.getHandlerFor(psiVariable, null != result.singularAnnotation); result.builderElementHandler = SingularHandlerFactory.getHandlerFor(psiVariable, null != result.singularAnnotation);
result.nullAnnotationLibrary = LombokNullAnnotationLibraryDefned.NONE; result.nullAnnotationLibrary = LombokNullAnnotationLibraryDefned.NONE;

View File

@@ -88,7 +88,7 @@ public final class DelegateHandler {
} }
private static Collection<PsiType> collectDelegateTypes(PsiAnnotation psiAnnotation, PsiType psiType) { private static Collection<PsiType> collectDelegateTypes(PsiAnnotation psiAnnotation, PsiType psiType) {
Collection<PsiType> types = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, TYPES_PARAMETER, PsiType.class); Collection<PsiType> types = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, TYPES_PARAMETER, PsiType.class, List.of());
if (types.isEmpty()) { if (types.isEmpty()) {
types = Collections.singletonList(psiType); types = Collections.singletonList(psiType);
} }
@@ -129,7 +129,7 @@ public final class DelegateHandler {
} }
private static Collection<PsiType> collectExcludeTypes(PsiAnnotation psiAnnotation) { private static Collection<PsiType> collectExcludeTypes(PsiAnnotation psiAnnotation) {
return PsiAnnotationUtil.getAnnotationValues(psiAnnotation, EXCLUDES_PARAMETER, PsiType.class); return PsiAnnotationUtil.getAnnotationValues(psiAnnotation, EXCLUDES_PARAMETER, PsiType.class, List.of());
} }
public static <T extends PsiMember & PsiNamedElement> void generateElements(@NotNull T psiElement, public static <T extends PsiMember & PsiNamedElement> void generateElements(@NotNull T psiElement,

View File

@@ -100,9 +100,9 @@ public final class EqualsAndHashCodeToStringHandler {
final Collection<String> excludeProperty; final Collection<String> excludeProperty;
if (!explicitOf) { if (!explicitOf) {
ofProperty = Collections.emptyList(); ofProperty = Collections.emptyList();
excludeProperty = makeSet(PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class)); excludeProperty = makeSet(PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class, List.of()));
} else { } else {
ofProperty = makeSet(PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class)); ofProperty = makeSet(PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class, List.of()));
excludeProperty = Collections.emptyList(); excludeProperty = Collections.emptyList();
} }

View File

@@ -13,6 +13,7 @@ import com.intellij.util.containers.ContainerUtil;
import de.plushnikov.intellij.plugin.LombokClassNames; import de.plushnikov.intellij.plugin.LombokClassNames;
import de.plushnikov.intellij.plugin.psi.LombokExtensionMethod; import de.plushnikov.intellij.plugin.psi.LombokExtensionMethod;
import de.plushnikov.intellij.plugin.psi.LombokLightParameter; import de.plushnikov.intellij.plugin.psi.LombokLightParameter;
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil; import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil;
import de.plushnikov.intellij.plugin.util.PsiClassUtil; import de.plushnikov.intellij.plugin.util.PsiClassUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -43,10 +44,10 @@ public final class ExtensionMethodsHelper {
@Nullable PsiClass context = PsiTreeUtil.getContextOfType(place, PsiClass.class); @Nullable PsiClass context = PsiTreeUtil.getContextOfType(place, PsiClass.class);
while (context != null) { while (context != null) {
final @Nullable PsiAnnotation annotation = context.getAnnotation(LombokClassNames.EXTENSION_METHOD); final @Nullable PsiAnnotation annotation = PsiAnnotationSearchUtil.findAnnotation(context, LombokClassNames.EXTENSION_METHOD);
if (annotation != null) { if (annotation != null) {
final Set<PsiClass> providers = PsiAnnotationUtil.getAnnotationValues(annotation, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME, PsiType.class).stream() final Set<PsiClass> providers = PsiAnnotationUtil.getAnnotationValues(annotation, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME, PsiType.class, List.of()).stream()
.filter(PsiClassType.class::isInstance) .filter(PsiClassType.class::isInstance)
.map(PsiClassType.class::cast) .map(PsiClassType.class::cast)
.map(PsiClassType::resolve) .map(PsiClassType::resolve)

View File

@@ -1,6 +1,9 @@
package de.plushnikov.intellij.plugin.provider; package de.plushnikov.intellij.plugin.provider;
import com.intellij.lang.java.JavaLanguage; import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.PossiblyDumbAware;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider; import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.augment.PsiExtensionMethod; import com.intellij.psi.augment.PsiExtensionMethod;
@@ -28,7 +31,7 @@ import static de.plushnikov.intellij.plugin.util.LombokLibraryUtil.hasLombokLibr
* *
* @author Plushnikov Michail * @author Plushnikov Michail
*/ */
public final class LombokAugmentProvider extends PsiAugmentProvider { public final class LombokAugmentProvider extends PsiAugmentProvider implements PossiblyDumbAware {
private static final class Holder { private static final class Holder {
static final Collection<ModifierProcessor> modifierProcessors = LombokProcessorManager.getLombokModifierProcessors(); static final Collection<ModifierProcessor> modifierProcessors = LombokProcessorManager.getLombokModifierProcessors();
} }
@@ -36,6 +39,11 @@ public final class LombokAugmentProvider extends PsiAugmentProvider {
public LombokAugmentProvider() { public LombokAugmentProvider() {
} }
@Override
public boolean isDumbAware() {
return Registry.is("lombok.dumb.mode.enabled", false);
}
@NotNull @NotNull
@Override @Override
protected Set<String> transformModifiers(@NotNull PsiModifierList modifierList, @NotNull final Set<String> modifiers) { protected Set<String> transformModifiers(@NotNull PsiModifierList modifierList, @NotNull final Set<String> modifiers) {
@@ -47,18 +55,30 @@ public final class LombokAugmentProvider extends PsiAugmentProvider {
// make copy of original modifiers // make copy of original modifiers
Set<String> result = new HashSet<>(modifiers); Set<String> result = new HashSet<>(modifiers);
// Loop through all available processors and give all of them a chance to respond DumbService dumbService = DumbService.getInstance(modifierList.getProject());
for (ModifierProcessor processor : Holder.modifierProcessors) { Runnable runnable = () -> {
if (processor.isSupported(modifierList)) { // Loop through all available processors and give all of them a chance to respond
processor.transformModifiers(modifierList, result); for (ModifierProcessor processor : Holder.modifierProcessors) {
if (processor.isSupported(modifierList)) {
processor.transformModifiers(modifierList, result);
}
} }
};
if (dumbService.isDumb() && !dumbService.isAlternativeResolveEnabled()) {
dumbService.runWithAlternativeResolveEnabled(() -> runnable.run());
} }
else {
runnable.run();
}
return result; return result;
} }
@Override @Override
public boolean canInferType(@NotNull PsiTypeElement typeElement) { public boolean canInferType(@NotNull PsiTypeElement typeElement) {
//skip if dumb mode, allow only `getAugments`
if (DumbService.isDumb(typeElement.getProject())) return false;
return hasLombokLibrary(typeElement.getProject()) && ValProcessor.canInferType(typeElement); return hasLombokLibrary(typeElement.getProject()) && ValProcessor.canInferType(typeElement);
} }
@@ -75,7 +95,10 @@ public final class LombokAugmentProvider extends PsiAugmentProvider {
//see com.intellij.java.lomboktest.LombokHighlightingTest.testGetterLazyVariableNotInitialized //see com.intellij.java.lomboktest.LombokHighlightingTest.testGetterLazyVariableNotInitialized
@Override @Override
protected boolean fieldInitializerMightBeChanged(@NotNull PsiField field) { protected boolean fieldInitializerMightBeChanged(@NotNull PsiField field) {
if (field.hasAnnotation(LombokClassNames.BUILDER_DEFAULT)) { //skip if dumb mode, allow only `getAugments`
if (DumbService.isDumb(field.getProject())) return false;
if (PsiAnnotationSearchUtil.isAnnotatedWith(field, LombokClassNames.BUILDER_DEFAULT)) {
return true; return true;
} }
@@ -104,6 +127,9 @@ public final class LombokAugmentProvider extends PsiAugmentProvider {
@Nullable @Nullable
@Override @Override
protected PsiType inferType(@NotNull PsiTypeElement typeElement) { protected PsiType inferType(@NotNull PsiTypeElement typeElement) {
//skip if dumb mode, allow only `getAugments`
if (DumbService.isDumb(typeElement.getProject())) return null;
return hasLombokLibrary(typeElement.getProject()) ? ValProcessor.inferType(typeElement) : null; return hasLombokLibrary(typeElement.getProject()) ? ValProcessor.inferType(typeElement) : null;
} }
@@ -145,7 +171,10 @@ public final class LombokAugmentProvider extends PsiAugmentProvider {
// All invoker of AugmentProvider already make caching, // All invoker of AugmentProvider already make caching,
// and we want to try to skip recursive calls completely // and we want to try to skip recursive calls completely
DumbService dumbService = DumbService.getInstance(psiClass.getProject());
if (DumbService.isDumb(psiClass.getProject()) && !dumbService.isAlternativeResolveEnabled()) {
return dumbService.computeWithAlternativeResolveEnabled(()-> getPsis(psiClass, type, nameHint));
}
return getPsis(psiClass, type, nameHint); return getPsis(psiClass, type, nameHint);
} }
@@ -165,6 +194,9 @@ public final class LombokAugmentProvider extends PsiAugmentProvider {
protected List<PsiExtensionMethod> getExtensionMethods(@NotNull PsiClass aClass, protected List<PsiExtensionMethod> getExtensionMethods(@NotNull PsiClass aClass,
@NotNull String nameHint, @NotNull String nameHint,
@NotNull PsiElement context) { @NotNull PsiElement context) {
//skip if dumb mode, allow only `getAugments`
if (DumbService.isDumb(aClass.getProject())) return Collections.emptyList();
if (!hasLombokLibrary(context.getProject())) { if (!hasLombokLibrary(context.getProject())) {
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@@ -1,5 +1,6 @@
package de.plushnikov.intellij.plugin.psi; package de.plushnikov.intellij.plugin.psi;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.impl.ElementPresentationUtil; import com.intellij.psi.impl.ElementPresentationUtil;
@@ -101,7 +102,16 @@ public class LombokLightClassBuilder extends LightPsiClassBuilder implements Psi
@Override @Override
public PsiField @NotNull [] getFields() { public PsiField @NotNull [] getFields() {
if (null == myFields) { if (null == myFields) {
Collection<PsiField> generatedFields = fieldSupplier.apply(this); Collection<PsiField> generatedFields;
DumbService dumbService = DumbService.getInstance(getProject());
if (dumbService.isDumb() && !dumbService.isAlternativeResolveEnabled()) {
generatedFields = dumbService.computeWithAlternativeResolveEnabled(
() -> fieldSupplier.apply(this)
);
}
else {
generatedFields = fieldSupplier.apply(this);
}
myFields = generatedFields.toArray(PsiField.EMPTY_ARRAY); myFields = generatedFields.toArray(PsiField.EMPTY_ARRAY);
fieldSupplier = c -> Collections.emptyList(); fieldSupplier = c -> Collections.emptyList();
} }
@@ -111,7 +121,16 @@ public class LombokLightClassBuilder extends LightPsiClassBuilder implements Psi
@Override @Override
public PsiMethod @NotNull [] getMethods() { public PsiMethod @NotNull [] getMethods() {
if (null == myMethods) { if (null == myMethods) {
Collection<PsiMethod> generatedMethods = methodSupplier.apply(this); Collection<PsiMethod> generatedMethods;
DumbService dumbService = DumbService.getInstance(getProject());
if (dumbService.isDumb() && !dumbService.isAlternativeResolveEnabled()) {
generatedMethods = dumbService.computeWithAlternativeResolveEnabled(
() -> methodSupplier.apply(this)
);
}
else {
generatedMethods = methodSupplier.apply(this);
}
myMethods = generatedMethods.toArray(PsiMethod.EMPTY_ARRAY); myMethods = generatedMethods.toArray(PsiMethod.EMPTY_ARRAY);
methodSupplier = c -> Collections.emptyList(); methodSupplier = c -> Collections.emptyList();
} }

View File

@@ -3,6 +3,7 @@ package de.plushnikov.intellij.plugin.psi;
import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil; import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.lang.java.JavaLanguage; import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
@@ -189,7 +190,15 @@ public class LombokLightMethodBuilder extends LightMethodBuilder implements Synt
Function<LombokLightMethodBuilder, String> builderBodyFunction = myBuilderBodyFunction; Function<LombokLightMethodBuilder, String> builderBodyFunction = myBuilderBodyFunction;
if (null == myBodyCodeBlock && (bodyAsText != null || builderBodyFunction != null)) { if (null == myBodyCodeBlock && (bodyAsText != null || builderBodyFunction != null)) {
if (bodyAsText == null) { if (bodyAsText == null) {
bodyAsText = builderBodyFunction.apply(this); DumbService dumbService = DumbService.getInstance(getProject());
if (dumbService.isDumb() && !dumbService.isAlternativeResolveEnabled()) {
bodyAsText = dumbService.computeWithAlternativeResolveEnabled(
() -> builderBodyFunction.apply(this)
);
}
else {
bodyAsText = builderBodyFunction.apply(this);
}
} }
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getProject()); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getProject());
myBodyCodeBlock = elementFactory.createCodeBlockFromText("{" + bodyAsText + "}", this); myBodyCodeBlock = elementFactory.createCodeBlockFromText("{" + bodyAsText + "}", this);

View File

@@ -1,5 +1,6 @@
package de.plushnikov.intellij.plugin.util; package de.plushnikov.intellij.plugin.util;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtil;
@@ -84,18 +85,24 @@ public final class LombokProcessorUtil {
} }
public static Collection<String> getOldOnX(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameterName) { public static Collection<String> getOldOnX(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameterName) {
PsiAnnotationMemberValue onXValue = psiAnnotation.hasAttribute(parameterName) ? psiAnnotation.findAttributeValue(parameterName) : null; PsiAnnotationMemberValue onXValue;
if (DumbService.isDumb(psiAnnotation.getProject())) {
onXValue = psiAnnotation.findDeclaredAttributeValue(parameterName);
}
else {
onXValue = psiAnnotation.hasAttribute(parameterName) ? psiAnnotation.findAttributeValue(parameterName) : null;
}
if (!(onXValue instanceof PsiAnnotation)) { if (!(onXValue instanceof PsiAnnotation)) {
return Collections.emptyList(); return Collections.emptyList();
} }
Collection<PsiAnnotation> annotations = PsiAnnotationUtil.getAnnotationValues((PsiAnnotation)onXValue, "value", PsiAnnotation.class); Collection<PsiAnnotation> annotations = PsiAnnotationUtil.getAnnotationValues((PsiAnnotation)onXValue, "value", PsiAnnotation.class, List.of());
return collectAnnotationStrings(annotations); return collectAnnotationStrings(annotations);
} }
public static Collection<String> getNewOnX(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameterName) { public static Collection<String> getNewOnX(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameterName) {
if (psiAnnotation.hasAttribute(parameterName)) { if (DumbService.isDumb(psiAnnotation.getProject()) || psiAnnotation.hasAttribute(parameterName)) {
final Collection<PsiAnnotation> annotations = final Collection<PsiAnnotation> annotations =
PsiAnnotationUtil.getAnnotationValues(psiAnnotation, parameterName, PsiAnnotation.class); PsiAnnotationUtil.getAnnotationValues(psiAnnotation, parameterName, PsiAnnotation.class, List.of());
return collectAnnotationStrings(annotations); return collectAnnotationStrings(annotations);
} }
return Collections.emptyList(); return Collections.emptyList();

View File

@@ -1,9 +1,9 @@
package de.plushnikov.intellij.plugin.util; package de.plushnikov.intellij.plugin.util;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiAnnotation; import com.intellij.psi.*;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -14,13 +14,60 @@ public final class PsiAnnotationSearchUtil {
@Nullable @Nullable
public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String annotationFQN) { public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String annotationFQN) {
if (isDumbMode(psiModifierListOwner)) {
return findAnnotationInDumbMode(psiModifierListOwner, annotationFQN);
}
return psiModifierListOwner.getAnnotation(annotationFQN); return psiModifierListOwner.getAnnotation(annotationFQN);
} }
private static @Nullable PsiAnnotation findAnnotationInDumbMode(@NotNull PsiModifierListOwner owner, @NotNull String annotationFQN) {
for (PsiAnnotation annotation : owner.getAnnotations()) {
if (hasQualifiedNameInDumbMode(annotation, annotationFQN)) {
return annotation;
}
}
return null;
}
private static boolean hasQualifiedNameInDumbMode(PsiAnnotation annotation, @NotNull String fqn) {
PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement == null) return false;
String qualifiedName = referenceElement.getReferenceName();
if (qualifiedName == null) return false;
if (qualifiedName.equals(fqn)) return true;
String referenceElementText = referenceElement.getText();
if (referenceElementText != null && referenceElementText.equals(fqn)) return true;
if (!fqn.endsWith(qualifiedName)) return false;
PsiFile containingFile = annotation.getContainingFile();
if (!(containingFile instanceof PsiJavaFile javaFile)) {
return false;
}
String packageName = StringUtil.getPackageName(fqn);
PsiImportList importList = javaFile.getImportList();
if (importList == null) return false;
int indexMayByOuterClass = fqn.length() - qualifiedName.length() - 1;
String mayBeOuterClass = indexMayByOuterClass > 0 ? fqn.substring(0, indexMayByOuterClass) : null;
return importList.findOnDemandImportStatement(packageName) != null ||
importList.findSingleClassImportStatement(fqn) != null ||
(mayBeOuterClass!=null && importList.findSingleClassImportStatement(mayBeOuterClass) != null);
}
private static boolean isDumbMode(@NotNull PsiElement context) {
Project project = context.getProject();
return DumbService.isDumb(project);
}
@Nullable @Nullable
public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, String @NotNull ... annotationFQNs) { public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, String @NotNull ... annotationFQNs) {
boolean isDumbMode = isDumbMode(psiModifierListOwner);
for (String annotationFQN : annotationFQNs) { for (String annotationFQN : annotationFQNs) {
PsiAnnotation annotation = psiModifierListOwner.getAnnotation(annotationFQN); PsiAnnotation annotation;
if (isDumbMode) {
annotation = findAnnotationInDumbMode(psiModifierListOwner, annotationFQN);
}
else {
annotation = psiModifierListOwner.getAnnotation(annotationFQN);
}
if (annotation != null) { if (annotation != null) {
return annotation; return annotation;
} }
@@ -29,6 +76,9 @@ public final class PsiAnnotationSearchUtil {
} }
public static boolean isAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String annotationFQN) { public static boolean isAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String annotationFQN) {
if (isDumbMode(psiModifierListOwner)) {
return findAnnotationInDumbMode(psiModifierListOwner, annotationFQN) != null;
}
return psiModifierListOwner.hasAnnotation(annotationFQN); return psiModifierListOwner.hasAnnotation(annotationFQN);
} }
@@ -79,6 +129,9 @@ public final class PsiAnnotationSearchUtil {
public static boolean checkAnnotationHasOneOfFQNs(@NotNull PsiAnnotation psiAnnotation, public static boolean checkAnnotationHasOneOfFQNs(@NotNull PsiAnnotation psiAnnotation,
String @NotNull ... annotationFQNs) { String @NotNull ... annotationFQNs) {
if (isDumbMode(psiAnnotation)) {
return ContainerUtil.or(annotationFQNs, fqn-> hasQualifiedNameInDumbMode(psiAnnotation, fqn));
}
return ContainerUtil.or(annotationFQNs, psiAnnotation::hasQualifiedName); return ContainerUtil.or(annotationFQNs, psiAnnotation::hasQualifiedName);
} }
} }

View File

@@ -1,6 +1,7 @@
package de.plushnikov.intellij.plugin.util; package de.plushnikov.intellij.plugin.util;
import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
@@ -10,6 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
/** /**
* Some util methods for annotation processing * Some util methods for annotation processing
@@ -35,9 +37,19 @@ public final class PsiAnnotationUtil {
} }
@NotNull @NotNull
public static <T> Collection<T> getAnnotationValues(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameter, @NotNull Class<T> asClass) { public static <T> Collection<T> getAnnotationValues(@NotNull PsiAnnotation psiAnnotation,
@NotNull String parameter,
@NotNull Class<T> asClass,
@NotNull List<T> defaultDumbValue) {
Collection<T> result = Collections.emptyList(); Collection<T> result = Collections.emptyList();
PsiAnnotationMemberValue attributeValue = psiAnnotation.findAttributeValue(parameter); PsiAnnotationMemberValue attributeValue;
if (DumbService.isDumb(psiAnnotation.getProject())) {
attributeValue = psiAnnotation.findDeclaredAttributeValue(parameter);
if (attributeValue == null) return defaultDumbValue;
}
else {
attributeValue = psiAnnotation.findAttributeValue(parameter);
}
if (attributeValue instanceof PsiArrayInitializerMemberValue) { if (attributeValue instanceof PsiArrayInitializerMemberValue) {
final PsiAnnotationMemberValue[] memberValues = ((PsiArrayInitializerMemberValue) attributeValue).getInitializers(); final PsiAnnotationMemberValue[] memberValues = ((PsiArrayInitializerMemberValue) attributeValue).getInitializers();
result = new ArrayList<>(memberValues.length); result = new ArrayList<>(memberValues.length);

View File

@@ -250,6 +250,9 @@
<jvm.logging implementation="de.plushnikov.intellij.plugin.logging.LombokLog4j2Logger"/> <jvm.logging implementation="de.plushnikov.intellij.plugin.logging.LombokLog4j2Logger"/>
<jvm.logging implementation="de.plushnikov.intellij.plugin.logging.LombokLog4jLogger"/> <jvm.logging implementation="de.plushnikov.intellij.plugin.logging.LombokLog4jLogger"/>
<jvm.logging implementation="de.plushnikov.intellij.plugin.logging.LombokApacheCommonsLogger"/> <jvm.logging implementation="de.plushnikov.intellij.plugin.logging.LombokApacheCommonsLogger"/>
<registryKey key="lombok.dumb.mode.enabled" defaultValue="true" restartRequired="true"
description="Lombok augment works in dumb mode"/>
</extensions> </extensions>
<projectListeners> <projectListeners>

View File

@@ -2,10 +2,12 @@ package de.plushnikov.intellij.plugin;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.PomNamedTarget; import com.intellij.pom.PomNamedTarget;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.DumbModeTestUtils;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import de.plushnikov.intellij.plugin.util.PsiElementUtil; import de.plushnikov.intellij.plugin.util.PsiElementUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -48,6 +50,8 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
} }
public void doTest(String testName) { public void doTest(String testName) {
DumbModeTestUtils.runInDumbModeSynchronously(getProject(),
() -> compareFiles(loadBeforeLombokFile(testName), loadAfterDeLombokFile(testName)));
compareFiles(loadBeforeLombokFile(testName), loadAfterDeLombokFile(testName)); compareFiles(loadBeforeLombokFile(testName), loadAfterDeLombokFile(testName));
} }
@@ -147,11 +151,13 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
assertEquals("Initializers are not equals ", afterInitializerText, beforeInitializerText); assertEquals("Initializers are not equals ", afterInitializerText, beforeInitializerText);
} }
private static void compareType(PsiType beforeType, PsiType afterType, PomNamedTarget whereTarget) { private void compareType(PsiType beforeType, PsiType afterType, PomNamedTarget whereTarget) {
if (null != beforeType && null != afterType) { if (null != beforeType && null != afterType) {
final String afterText = stripJavaLang(afterType.getCanonicalText()); DumbService.getInstance(getProject()).runWithAlternativeResolveEnabled(() -> {
final String beforeText = stripJavaLang(beforeType.getCanonicalText()); final String afterText = stripJavaLang(afterType.getCanonicalText());
assertEquals(String.format("Types are not equal for element: %s", whereTarget.getName()), afterText, beforeText); final String beforeText = stripJavaLang(beforeType.getCanonicalText());
assertEquals(String.format("Types are not equal for element: %s", whereTarget.getName()), afterText, beforeText);
});
} }
} }
@@ -184,15 +190,16 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
} }
private void compareAnnotations(PsiModifierList beforeModifierList, PsiModifierList afterModifierList) { private void compareAnnotations(PsiModifierList beforeModifierList, PsiModifierList afterModifierList) {
DumbService dumbService = DumbService.getInstance(beforeModifierList.getProject());
if (shouldCompareAnnotations()) { if (shouldCompareAnnotations()) {
Collection<String> beforeAnnotations = Arrays.stream(beforeModifierList.getAnnotations()) Collection<String> beforeAnnotations = Arrays.stream(beforeModifierList.getAnnotations())
.map(PsiAnnotation::getQualifiedName) .map(an-> dumbService.computeWithAlternativeResolveEnabled(()->an.getQualifiedName()))
.filter(Pattern.compile("lombok.*").asPredicate().negate().or(LombokClassNames.NON_NULL::equals)) .filter(Pattern.compile("lombok.*").asPredicate().negate().or(LombokClassNames.NON_NULL::equals))
.filter(Pattern.compile(annotationToComparePattern()).asPredicate()) .filter(Pattern.compile(annotationToComparePattern()).asPredicate())
.filter(Predicate.not(annotationsToIgnoreList()::contains)) .filter(Predicate.not(annotationsToIgnoreList()::contains))
.toList(); .toList();
Collection<String> afterAnnotations = Arrays.stream(afterModifierList.getAnnotations()) Collection<String> afterAnnotations = Arrays.stream(afterModifierList.getAnnotations())
.map(PsiAnnotation::getQualifiedName) .map(an-> dumbService.computeWithAlternativeResolveEnabled(()->an.getQualifiedName()))
.filter(Pattern.compile(annotationToComparePattern()).asPredicate()) .filter(Pattern.compile(annotationToComparePattern()).asPredicate())
.filter(Predicate.not(annotationsToIgnoreList()::contains)) .filter(Predicate.not(annotationsToIgnoreList()::contains))
.toList(); .toList();
@@ -204,8 +211,10 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
// compare annotations parameter list // compare annotations parameter list
for (PsiAnnotation beforeAnnotation : beforeModifierList.getAnnotations()) { for (PsiAnnotation beforeAnnotation : beforeModifierList.getAnnotations()) {
String qualifiedName = beforeAnnotation.getQualifiedName(); String qualifiedName =
PsiAnnotation afterAnnotation = afterModifierList.findAnnotation(qualifiedName); dumbService.computeWithAlternativeResolveEnabled(() -> beforeAnnotation.getQualifiedName());
PsiAnnotation afterAnnotation =
dumbService.computeWithAlternativeResolveEnabled(() -> afterModifierList.findAnnotation(qualifiedName));
if (null != afterAnnotation) { if (null != afterAnnotation) {
Map<String, String> beforeParameter = Stream.of(beforeAnnotation.getParameterList().getAttributes()) Map<String, String> beforeParameter = Stream.of(beforeAnnotation.getParameterList().getAttributes())
.collect(Collectors.toMap(PsiNameValuePair::getAttributeName, p -> p.getValue().getText())); .collect(Collectors.toMap(PsiNameValuePair::getAttributeName, p -> p.getValue().getText()));
@@ -287,8 +296,10 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
private static Collection<String> mapToTypeString(PsiParameterList compareMethodParameterList) { private static Collection<String> mapToTypeString(PsiParameterList compareMethodParameterList) {
Collection<String> result = new ArrayList<>(); Collection<String> result = new ArrayList<>();
final PsiParameter[] compareMethodParameterListParameters = compareMethodParameterList.getParameters(); final PsiParameter[] compareMethodParameterListParameters = compareMethodParameterList.getParameters();
DumbService dumbService = DumbService.getInstance(compareMethodParameterList.getProject());
for (PsiParameter compareMethodParameterListParameter : compareMethodParameterListParameters) { for (PsiParameter compareMethodParameterListParameter : compareMethodParameterListParameters) {
result.add(stripJavaLang(compareMethodParameterListParameter.getType().getCanonicalText())); PsiType type = compareMethodParameterListParameter.getType();
result.add(stripJavaLang(dumbService.computeWithAlternativeResolveEnabled(() -> type.getCanonicalText())));
} }
return result; return result;
} }
@@ -303,10 +314,12 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
PsiClassType[] afterTypes = afterThrows.getReferencedTypes(); PsiClassType[] afterTypes = afterThrows.getReferencedTypes();
assertEquals("Throws counts are different for Method :" + psiMethod.getName(), beforeTypes.length, afterTypes.length); assertEquals("Throws counts are different for Method :" + psiMethod.getName(), beforeTypes.length, afterTypes.length);
DumbService dumbService = DumbService.getInstance(psiMethod.getProject());
for (PsiClassType beforeType : beforeTypes) { for (PsiClassType beforeType : beforeTypes) {
boolean found = false; boolean found = false;
for (PsiClassType afterType : afterTypes) { for (PsiClassType afterType : afterTypes) {
if (beforeType.equals(afterType)) { boolean equals = dumbService.computeWithAlternativeResolveEnabled(()->beforeType.equals(afterType));
if (equals) {
found = true; found = true;
break; break;
} }
@@ -332,7 +345,9 @@ public abstract class AbstractLombokParsingTestCase extends AbstractLombokLightC
ContainerUtil.map(afterConstructor.getParameterList().getParameters(), PsiParameter::getType); ContainerUtil.map(afterConstructor.getParameterList().getParameters(), PsiParameter::getType);
for (PsiMethod beforeConstructor : beforeConstructors) { for (PsiMethod beforeConstructor : beforeConstructors) {
if (PsiElementUtil.methodMatches(beforeConstructor, null, null, afterConstructor.getName(), afterConstructorParameterTypes)) { boolean methodMatches = DumbService.getInstance(getProject()).computeWithAlternativeResolveEnabled(
() -> PsiElementUtil.methodMatches(beforeConstructor, null, null, afterConstructor.getName(), afterConstructorParameterTypes));
if (methodMatches) {
final PsiModifierList intellijConstructorModifierList = beforeConstructor.getModifierList(); final PsiModifierList intellijConstructorModifierList = beforeConstructor.getModifierList();
compareModifiers(intellijConstructorModifierList, theirsFieldModifierList); compareModifiers(intellijConstructorModifierList, theirsFieldModifierList);

View File

@@ -0,0 +1,41 @@
package de.plushnikov.intellij.plugin.configsystem;
import com.intellij.testFramework.DumbModeTestUtils;
public class GetterDumbModeTest extends AbstractLombokConfigSystemTestCase {
@Override
protected String getBasePath() {
return super.getBasePath() + "/configsystem/getter";
}
public void testDumb$GetterClassTest() {
final String fullFileName = getTestName(true).replace('$', '/') + ".java";
final int lastIndexOf = fullFileName.lastIndexOf('/');
final String subPath = fullFileName.substring(0, lastIndexOf);
final String fileName = fullFileName.substring(lastIndexOf + 1);
DumbModeTestUtils.runInDumbModeSynchronously(
getProject(),
() -> {
myFixture.copyFileToProject(subPath + "/before/lombok.config", subPath + "/before/lombok.config");
doTest(subPath + "/before/inner/" + fileName, subPath + "/after/inner/" + fileName);
}
);
}
public void testDumbStopBubbling$GetterClassTest() {
final String fullFileName = getTestName(true).replace('$', '/') + ".java";
final int lastIndexOf = fullFileName.lastIndexOf('/');
final String subPath = fullFileName.substring(0, lastIndexOf);
final String fileName = fullFileName.substring(lastIndexOf + 1);
DumbModeTestUtils.runInDumbModeSynchronously(
getProject(),
() -> {
myFixture.copyFileToProject(subPath + "/before/inner/lombok.config", subPath + "/before/inner/lombok.config");
myFixture.copyFileToProject(subPath + "/before/lombok.config", subPath + "/before/lombok.config");
doTest(subPath + "/before/inner/" + fileName, subPath + "/after/inner/" + fileName);
}
);
}
}

View File

@@ -1,5 +1,7 @@
package de.plushnikov.intellij.plugin.lombokconfig; package de.plushnikov.intellij.plugin.lombokconfig;
import com.intellij.mock.MockDumbService;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
@@ -64,6 +66,7 @@ public class ConfigDiscoveryTest {
} }
}; };
when(project.getService(DumbService.class)).thenReturn(new MockDumbService(project));
when(psiFile.getProject()).thenReturn(project); when(psiFile.getProject()).thenReturn(project);
when(psiClass.getContainingFile()).thenReturn(psiFile); when(psiClass.getContainingFile()).thenReturn(psiFile);
when(psiFile.getOriginalFile()).thenReturn(psiFile); when(psiFile.getOriginalFile()).thenReturn(psiFile);

View File

@@ -0,0 +1,32 @@
public class GetterClassTest {
private int intProperty;
private String stringProperty;
private boolean booleanProperty;
private Boolean booleanObjectProperty;
public static void main(String[] args) {
final GetterClassTest test = new GetterClassTest();
test.getIntProperty();
test.getStringProperty();
test.getBooleanObjectProperty();
test.getBooleanProperty();
}
public int getIntProperty() {
return this.intProperty;
}
public String getStringProperty() {
return this.stringProperty;
}
public boolean getBooleanProperty() {
return this.booleanProperty;
}
public Boolean getBooleanObjectProperty() {
return this.booleanObjectProperty;
}
}

View File

@@ -0,0 +1,19 @@
import lombok.Getter;
@Getter
public class GetterClassTest {
private int intProperty;
private String stringProperty;
private boolean booleanProperty;
private Boolean booleanObjectProperty;
public static void main(String[] args) {
final GetterClassTest test = new GetterClassTest();
test.getIntProperty();
test.getStringProperty();
test.getBooleanObjectProperty();
test.getBooleanProperty();
}
}

View File

@@ -0,0 +1,3 @@
lombok.getter.noIsPrefix = true
config.stopBubbling = true

View File

@@ -0,0 +1,32 @@
public class GetterClassTest {
private int intProperty;
private String stringProperty;
private boolean booleanProperty;
private Boolean booleanObjectProperty;
public static void main(String[] args) {
final GetterClassTest test = new GetterClassTest();
test.getIntProperty();
test.getStringProperty();
test.getBooleanObjectProperty();
test.isBooleanProperty();
}
public int getIntProperty() {
return this.intProperty;
}
public String getStringProperty() {
return this.stringProperty;
}
public boolean isBooleanProperty() {
return this.booleanProperty;
}
public Boolean getBooleanObjectProperty() {
return this.booleanObjectProperty;
}
}

View File

@@ -0,0 +1,19 @@
import lombok.Getter;
@Getter
public class GetterClassTest {
private int intProperty;
private String stringProperty;
private boolean booleanProperty;
private Boolean booleanObjectProperty;
public static void main(String[] args) {
final GetterClassTest test = new GetterClassTest();
test.getIntProperty();
test.getStringProperty();
test.getBooleanObjectProperty();
test.isBooleanProperty();
}
}

View File

@@ -0,0 +1 @@
config.stopBubbling = true

View File

@@ -0,0 +1,2 @@
lombok.getter.noIsPrefix = true
config.stopBubbling = true