IDEA-172425 Support access to fields/methods with generic types
authorVitaliy.Bibaev <vitaliy.bibaev@jetbrains.com>
Tue, 20 Mar 2018 08:31:12 +0000 (11:31 +0300)
committerVitaliy.Bibaev <vitaliy.bibaev@jetbrains.com>
Thu, 22 Mar 2018 12:33:33 +0000 (15:33 +0300)
java/java-impl/src/com/intellij/refactoring/extractMethodObject/reflect/FieldReflectionAccessor.java
java/java-impl/src/com/intellij/refactoring/extractMethodObject/reflect/MethodReflectionAccessor.java
java/java-impl/src/com/intellij/refactoring/extractMethodObject/reflect/ReflectionAccessMethodBuilder.java

index 1cf868012b434547c611ca990a855a937533a459..83a6017fe2cd022bc9734f1bd31f9a809e2d657e 100644 (file)
@@ -87,21 +87,21 @@ public class FieldReflectionAccessor extends ReferenceReflectionAccessorBase<Fie
   private PsiMethod createPsiMethod(@NotNull FieldDescriptor descriptor, FieldAccessType accessType) {
     PsiClass outerClass = getOuterClass();
     PsiClass containingClass = descriptor.field.getContainingClass();
-    String returnType = PsiReflectionAccessUtil.getAccessibleReturnType(descriptor.field.getType());
     String className = containingClass == null ? null : ClassUtil.getJVMClassName(containingClass);
     String fieldName = descriptor.field.getName();
     if (className == null || fieldName == null) {
       LOG.warn("Code is incomplete. Class name or field name not found");
       return null;
     }
-    if (returnType == null) {
-      LOG.warn("Could not resolve return type");
-      return null;
-    }
 
     String methodName = PsiReflectionAccessUtil.getUniqueMethodName(outerClass, "accessToField" + StringUtil.capitalize(fieldName));
     ReflectionAccessMethodBuilder methodBuilder = new ReflectionAccessMethodBuilder(methodName);
     if (FieldAccessType.GET.equals(accessType)) {
+      String returnType = PsiReflectionAccessUtil.getAccessibleReturnType(resolveFieldType(descriptor));
+      if (returnType == null) {
+        LOG.warn("Could not resolve field type");
+        return null;
+      }
       methodBuilder.accessedField(className, fieldName)
                    .setReturnType(returnType);
     }
@@ -122,6 +122,12 @@ public class FieldReflectionAccessor extends ReferenceReflectionAccessorBase<Fie
            !PsiReflectionAccessUtil.isQualifierAccessible(expression.getQualifierExpression());
   }
 
+  @NotNull
+  private static PsiType resolveFieldType(@NotNull FieldDescriptor descriptor) {
+    PsiType rawType = descriptor.field.getType();
+    return descriptor.expression.advancedResolve(false).getSubstitutor().substitute(rawType);
+  }
+
   @Nullable
   private static String qualify(@NotNull FieldDescriptor descriptor) {
     String qualifier = PsiReflectionAccessUtil.extractQualifier(descriptor.expression);
index cb8fd2269d9466bd1d0c1f467e8ad284279cff05..b0047cb1fc06e599f636712a9dde72551f687078 100644 (file)
@@ -48,7 +48,7 @@ public class MethodReflectionAccessor extends ReflectionAccessorBase<MethodRefle
   @Override
   protected void grantAccess(@NotNull MethodCallDescriptor descriptor) {
     PsiClass outerClass = getOuterClass();
-    String returnType = PsiReflectionAccessUtil.getAccessibleReturnType(descriptor.method.getReturnType());
+    String returnType = PsiReflectionAccessUtil.getAccessibleReturnType(resolveMethodReturnType(descriptor));
     PsiClass containingClass = descriptor.method.getContainingClass();
     String containingClassName = containingClass == null ? null : ClassUtil.getJVMClassName(containingClass);
     String name = descriptor.method.getName();
@@ -87,6 +87,12 @@ public class MethodReflectionAccessor extends ReflectionAccessorBase<MethodRefle
            !PsiReflectionAccessUtil.isQualifierAccessible(referenceExpression.getQualifierExpression());
   }
 
+  @Nullable
+  private static PsiType resolveMethodReturnType(@NotNull MethodCallDescriptor descriptor) {
+    PsiSubstitutor substitutor = descriptor.callExpression.resolveMethodGenerics().getSubstitutor();
+    return substitutor.substitute(descriptor.method.getReturnType());
+  }
+
   @Nullable
   private static String qualify(@NotNull MethodCallDescriptor descriptor) {
     String qualifier = PsiReflectionAccessUtil.extractQualifier(descriptor.callExpression.getMethodExpression());
index c0c101758de73ec0eb1494724a910e4a3dd1a8c1..f212fcf92d62c18bb86078dd03cf29fc21501d5b 100644 (file)
@@ -5,6 +5,7 @@ import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.*;
 import com.intellij.psi.util.ClassUtil;
 import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.TypeConversionUtil;
 import com.intellij.refactoring.extractMethodObject.PsiReflectionAccessUtil;
 import com.intellij.util.SmartList;
 import one.util.streamex.StreamEx;
@@ -115,7 +116,7 @@ public class ReflectionAccessMethodBuilder {
     for (int i = 0; i < parameters.length; i++) {
       PsiParameter parameter = parameters[i];
       String name = parameter.getName();
-      PsiType type = parameter.getType();
+      PsiType type = TypeConversionUtil.erasure(parameter.getType());
       myParameters.add(new ParameterInfo(type.getCanonicalText(), name == null ? "arg" + i : name, extractJvmType(type)));
     }