mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
[java-psi] Rework extension methods support, according to review IJ-CR-4151
GitOrigin-RevId: 29d547dc38b2feba7e55b8fcfb420094341219b8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
52a6df4733
commit
33edc0ffa4
@@ -5,7 +5,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.augment.PsiExtensionMethod;
|
||||
import com.intellij.psi.impl.light.LightRecordCanonicalConstructor;
|
||||
import com.intellij.psi.impl.light.LightRecordMember;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
@@ -152,11 +152,8 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem
|
||||
}
|
||||
}
|
||||
|
||||
if (refElement instanceof PsiMethod) {
|
||||
PsiMethod extensionMethod = PsiAugmentProvider.resolveExtensionMethod((PsiMethod)refElement);
|
||||
if (extensionMethod != null) {
|
||||
return extensionMethod;
|
||||
}
|
||||
if (refElement instanceof PsiExtensionMethod) {
|
||||
refElement = ((PsiExtensionMethod)refElement).getTargetMethod();
|
||||
}
|
||||
|
||||
if (refElement instanceof LightRecordMember) {
|
||||
|
||||
@@ -74,19 +74,10 @@ public abstract class PsiAugmentProvider {
|
||||
* @param context context where extension methods should be applicable
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
protected List<PsiMethod> getExtensionMethods(@NotNull PsiClass aClass, @NotNull String nameHint, @NotNull PsiElement context) {
|
||||
protected List<PsiExtensionMethod> getExtensionMethods(@NotNull PsiClass aClass, @NotNull String nameHint, @NotNull PsiElement context) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param method a method to resolve
|
||||
* @return target static method, or null if the supplied method is not an extension method
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
protected @Nullable PsiMethod getTargetMethod(@NotNull PsiMethod method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated invoke and override {@link #getAugments(PsiElement, Class, String)}.
|
||||
*/
|
||||
@@ -164,11 +155,11 @@ public abstract class PsiAugmentProvider {
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@NotNull
|
||||
public static List<PsiMethod> collectExtensionMethods(PsiClass aClass, @NotNull String nameHint, PsiElement context) {
|
||||
List<PsiMethod> extensionMethods = new SmartList<>();
|
||||
public static List<PsiExtensionMethod> collectExtensionMethods(PsiClass aClass, @NotNull String nameHint, PsiElement context) {
|
||||
List<PsiExtensionMethod> extensionMethods = new SmartList<>();
|
||||
forEach(aClass.getProject(), provider -> {
|
||||
List<PsiMethod> methods = provider.getExtensionMethods(aClass, nameHint, context);
|
||||
for (PsiMethod method : methods) {
|
||||
List<PsiExtensionMethod> methods = provider.getExtensionMethods(aClass, nameHint, context);
|
||||
for (PsiExtensionMethod method : methods) {
|
||||
try {
|
||||
PsiUtilCore.ensureValid(method);
|
||||
extensionMethods.add(method);
|
||||
@@ -185,25 +176,6 @@ public abstract class PsiAugmentProvider {
|
||||
return extensionMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param method a method to resolve
|
||||
* @return target static method, or null if the supplied method is not an extension method
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@Nullable
|
||||
public static PsiMethod resolveExtensionMethod(PsiMethod method) {
|
||||
Ref<PsiMethod> result = Ref.create();
|
||||
forEach(method.getProject(), provider -> {
|
||||
PsiMethod target = provider.getTargetMethod(method);
|
||||
if (target != null) {
|
||||
result.set(target);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getInferredType(@NotNull PsiTypeElement typeElement) {
|
||||
Ref<PsiType> result = Ref.create();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.augment;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An extension instance method that delegates to another method.
|
||||
* Does not exist normally in Java but may be supported by annotation processors or other language extensions.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface PsiExtensionMethod extends PsiMethod {
|
||||
/**
|
||||
* @return a target method
|
||||
*/
|
||||
@NotNull PsiMethod getTargetMethod();
|
||||
|
||||
/**
|
||||
* @return a target method parameter that corresponds to the receiver of this extension method;
|
||||
* null if the receiver does not correspond to any parameter of the target method.
|
||||
*/
|
||||
@Nullable PsiParameter getTargetReceiverParameter();
|
||||
|
||||
/**
|
||||
* @param index index of this method parameter
|
||||
* @return a target method parameter that corresponds to the parameter of this extension method having the specified index;
|
||||
* null if the specified parameter does not correspond to any parameter of the target method.
|
||||
*/
|
||||
@Nullable PsiParameter getTargetParameter(int index);
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.augment.PsiExtensionMethod;
|
||||
import com.intellij.psi.impl.java.stubs.PsiClassReferenceListStub;
|
||||
import com.intellij.psi.impl.source.ClassInnerStuffCache;
|
||||
import com.intellij.psi.impl.source.PsiImmediateClassType;
|
||||
@@ -359,7 +360,7 @@ public final class PsiClassImplUtil {
|
||||
}
|
||||
}
|
||||
if (type == MemberType.METHOD && psiClass != null && context != null) {
|
||||
List<PsiMethod> methods = PsiAugmentProvider.collectExtensionMethods(psiClass, name, context);
|
||||
List<PsiExtensionMethod> methods = PsiAugmentProvider.collectExtensionMethods(psiClass, name, context);
|
||||
if (!methods.isEmpty()) {
|
||||
if (result == null) result = new ArrayList<>();
|
||||
result.addAll(methods);
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.siyeh.ig.psiutils;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.augment.PsiExtensionMethod;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.MethodSignatureUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -438,11 +438,8 @@ public final class MethodCallUtils {
|
||||
PsiMethodCallExpression callForQualifier = tryCast(argumentParent.getParent(), PsiMethodCallExpression.class);
|
||||
if (callForQualifier != null) {
|
||||
PsiMethod method = callForQualifier.resolveMethod();
|
||||
if (method != null) {
|
||||
PsiMethod extensionMethod = PsiAugmentProvider.resolveExtensionMethod(method);
|
||||
if (extensionMethod != null) {
|
||||
return extensionMethod.getParameterList().getParameter(0);
|
||||
}
|
||||
if (method instanceof PsiExtensionMethod) {
|
||||
return ((PsiExtensionMethod)method).getTargetReceiverParameter();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -459,15 +456,11 @@ public final class MethodCallUtils {
|
||||
if (index == -1) return null;
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if (method == null) return null;
|
||||
PsiMethod extensionMethod = PsiAugmentProvider.resolveExtensionMethod(method);
|
||||
if (extensionMethod != null) {
|
||||
method = extensionMethod;
|
||||
index++;
|
||||
}
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (index >= parameters.length) return null;
|
||||
if (isVarArgCall(call) && index >= parameters.length - 1) return null;
|
||||
return parameters[index];
|
||||
PsiParameterList list = method.getParameterList();
|
||||
int count = list.getParametersCount();
|
||||
if (index >= count) return null;
|
||||
if (isVarArgCall(call) && index >= count - 1) return null;
|
||||
return method instanceof PsiExtensionMethod ? ((PsiExtensionMethod)method).getTargetParameter(index) : list.getParameter(index);
|
||||
}
|
||||
|
||||
private static int getParameterReferenceIndex(PsiMethodCallExpression call, PsiParameter parameter) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiExtensionMethod;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.SmartList;
|
||||
@@ -25,9 +26,9 @@ public class ExtensionMethodsHelper {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ExtensionMethodsHelper.class);
|
||||
|
||||
public static List<PsiMethod> getExtensionMethods(final @NotNull PsiClass targetClass,
|
||||
final @NotNull String nameHint,
|
||||
final @NotNull PsiElement place) {
|
||||
public static List<PsiExtensionMethod> getExtensionMethods(final @NotNull PsiClass targetClass,
|
||||
final @NotNull String nameHint,
|
||||
final @NotNull PsiElement place) {
|
||||
if (!(place instanceof PsiMethodCallExpression)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -38,7 +39,7 @@ public class ExtensionMethodsHelper {
|
||||
qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiClass) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PsiMethod> result = new SmartList<>();
|
||||
List<PsiExtensionMethod> result = new SmartList<>();
|
||||
|
||||
@Nullable PsiClass context = PsiTreeUtil.getContextOfType(place, PsiClass.class);
|
||||
while (context != null) {
|
||||
@@ -53,13 +54,13 @@ public class ExtensionMethodsHelper {
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!providers.isEmpty()) {
|
||||
List<PsiMethod> extensionMethods = collectExtensionMethods(providers, ((PsiMethodCallExpression)place), targetClass);
|
||||
List<PsiExtensionMethod> extensionMethods = collectExtensionMethods(providers, ((PsiMethodCallExpression)place), targetClass);
|
||||
extensionMethods
|
||||
.stream()
|
||||
.map(method -> MethodSignatureBackedByPsiMethod.create(method, PsiSubstitutor.EMPTY))
|
||||
.distinct()
|
||||
.filter(methodSignature -> !targetClass.getVisibleSignatures().contains(methodSignature))
|
||||
.forEach(methodSignature -> result.add(methodSignature.getMethod()));
|
||||
.forEach(methodSignature -> result.add((PsiExtensionMethod)methodSignature.getMethod()));
|
||||
}
|
||||
}
|
||||
context = PsiTreeUtil.getContextOfType(context, PsiClass.class);
|
||||
@@ -67,21 +68,21 @@ public class ExtensionMethodsHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<PsiMethod> collectExtensionMethods(final Set<PsiClass> providers,
|
||||
private static List<PsiExtensionMethod> collectExtensionMethods(final Set<PsiClass> providers,
|
||||
final PsiMethodCallExpression callExpression,
|
||||
final PsiClass targetClass) {
|
||||
List<PsiMethod> psiMethods = new ArrayList<>();
|
||||
List<PsiExtensionMethod> psiMethods = new ArrayList<>();
|
||||
providers.forEach(providerClass -> providerData(providerClass).forEach(function -> ContainerUtil.addIfNotNull(psiMethods, function.apply(targetClass, callExpression))));
|
||||
return psiMethods;
|
||||
}
|
||||
|
||||
public static List<BiFunction<PsiClass, PsiMethodCallExpression, PsiMethod>> providerData(final PsiClass providerClass) {
|
||||
public static List<BiFunction<PsiClass, PsiMethodCallExpression, PsiExtensionMethod>> providerData(final PsiClass providerClass) {
|
||||
return CachedValuesManager.getCachedValue(providerClass, () -> CachedValueProvider.Result
|
||||
.create(createProviderCandidates(providerClass), PsiModificationTracker.MODIFICATION_COUNT));
|
||||
}
|
||||
|
||||
private static List<BiFunction<PsiClass, PsiMethodCallExpression, PsiMethod>> createProviderCandidates(final PsiClass providerClass) {
|
||||
final List<BiFunction<PsiClass, PsiMethodCallExpression, PsiMethod>> result = new ArrayList<>();
|
||||
private static List<BiFunction<PsiClass, PsiMethodCallExpression, PsiExtensionMethod>> createProviderCandidates(final PsiClass providerClass) {
|
||||
final List<BiFunction<PsiClass, PsiMethodCallExpression, PsiExtensionMethod>> result = new ArrayList<>();
|
||||
for (PsiMethod providerStaticMethod : PsiClassUtil.collectClassStaticMethodsIntern(providerClass)) {
|
||||
if (providerStaticMethod.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
PsiParameter @NotNull [] parameters = providerStaticMethod.getParameterList().getParameters();
|
||||
@@ -93,7 +94,7 @@ public class ExtensionMethodsHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static LombokLightMethodBuilder createLightMethodBySignature(PsiMethod staticMethod,
|
||||
private static PsiExtensionMethod createLightMethodBySignature(PsiMethod staticMethod,
|
||||
PsiClass targetClass,
|
||||
PsiMethodCallExpression callExpression) {
|
||||
if (!staticMethod.getName().equals(callExpression.getMethodExpression().getReferenceName())) return null;
|
||||
@@ -124,7 +125,7 @@ public class ExtensionMethodsHelper {
|
||||
if (!method.equals(staticMethod) || !((MethodCandidateInfo)result).isApplicable()) return null;
|
||||
PsiSubstitutor substitutor = result.getSubstitutor();
|
||||
|
||||
final LombokLightMethodBuilder lightMethod = new LombokExtensionMethod(staticMethod);
|
||||
final LombokExtensionMethod lightMethod = new LombokExtensionMethod(staticMethod);
|
||||
lightMethod
|
||||
.addModifiers(PsiModifier.PUBLIC);
|
||||
PsiParameter @NotNull [] parameters = staticMethod.getParameterList().getParameters();
|
||||
@@ -156,14 +157,7 @@ public class ExtensionMethodsHelper {
|
||||
return lightMethod;
|
||||
}
|
||||
|
||||
public static @Nullable PsiMethod resolve(@NotNull PsiMethod method) {
|
||||
if (method instanceof LombokExtensionMethod) {
|
||||
return ((LombokExtensionMethod)method).myStaticMethod;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class LombokExtensionMethod extends LombokLightMethodBuilder {
|
||||
private static class LombokExtensionMethod extends LombokLightMethodBuilder implements PsiExtensionMethod {
|
||||
private final @NotNull PsiMethod myStaticMethod;
|
||||
|
||||
LombokExtensionMethod(@NotNull PsiMethod staticMethod) {
|
||||
@@ -173,5 +167,20 @@ public class ExtensionMethodsHelper {
|
||||
|
||||
@Override
|
||||
public boolean isEquivalentTo(final PsiElement another) { return myStaticMethod.isEquivalentTo(another); }
|
||||
|
||||
@Override
|
||||
public @NotNull PsiMethod getTargetMethod() {
|
||||
return myStaticMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PsiParameter getTargetReceiverParameter() {
|
||||
return myStaticMethod.getParameterList().getParameter(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PsiParameter getTargetParameter(int index) {
|
||||
return myStaticMethod.getParameterList().getParameter(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.util.RecursionGuard;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.augment.PsiExtensionMethod;
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
@@ -162,17 +163,12 @@ public class LombokAugmentProvider extends PsiAugmentProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<PsiMethod> getExtensionMethods(@NotNull PsiClass aClass,
|
||||
@NotNull String nameHint,
|
||||
@NotNull PsiElement context) {
|
||||
protected List<PsiExtensionMethod> getExtensionMethods(@NotNull PsiClass aClass,
|
||||
@NotNull String nameHint,
|
||||
@NotNull PsiElement context) {
|
||||
if (!LombokProjectValidatorActivity.hasLombokLibrary(context.getProject())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return ExtensionMethodsHelper.getExtensionMethods(aClass, nameHint, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable PsiMethod getTargetMethod(@NotNull PsiMethod method) {
|
||||
return ExtensionMethodsHelper.resolve(method);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user