xdev-software/intellij-plugin-save-actions

``Change visibility of field or method to lower access`` not working

AB-xdev opened this issue · 3 comments

Change visibility of field or method to lower access fails with

Caused by: java.lang.IllegalAccessError: 
class com.intellij.codeInspection.visibility.CustomAccessCanBeTightenedInspection$MyVisitor tried to access 
method 'int com.intellij.codeInspection.visibility.VisibilityInspection.getMinVisibilityLevel(com.intellij.psi.PsiMember)' 
(com.intellij.codeInspection.visibility.CustomAccessCanBeTightenedInspection$MyVisitor is in unnamed module of loader 
com.intellij.ide.plugins.cl.PluginClassLoader @2eed9be8; 
com.intellij.codeInspection.visibility.VisibilityInspection is in unnamed module of loader 
com.intellij.ide.plugins.cl.PluginClassLoader @5493c393)
...

Example code:

public class ABC
{
	public void testCaller()
	{
		this.test();
	}
	
	public void test()
	{
	}
}

The following classloaders are in use:
grafik

Okay so these different classloaders make it impossible to call package-private members.

Affected:

  • VisibilityInspection
    • int getMinVisibilityLevel(PsiMember)
    • boolean containsReferenceTo(PsiElement, PsiElement) (static)

The only solution that I see is to either use reflection or make these members public.

Reflection Git patch
diff --git a/src/main/java/com/intellij/codeInspection/visibility/CustomAccessCanBeTightenedInspection.java b/src/main/java/com/intellij/codeInspection/visibility/CustomAccessCanBeTightenedInspection.java
index eb473fb..b1028cc 100644
--- a/src/main/java/com/intellij/codeInspection/visibility/CustomAccessCanBeTightenedInspection.java
+++ b/src/main/java/com/intellij/codeInspection/visibility/CustomAccessCanBeTightenedInspection.java
@@ -31,9 +31,11 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;

+import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiPredicate;

 /**
  * A public version of {@link AccessCanBeTightenedInspection}.
@@ -209,7 +211,20 @@ public class CustomAccessCanBeTightenedInspection extends AbstractBaseJavaLocalI
             final PsiFile memberFile = member.getContainingFile();
             Project project = memberFile.getProject();

-            int level = myVisibilityInspection.getMinVisibilityLevel(member);
+            int level;
+            try {
+                final Method getMinVisibilityLevel = myVisibilityInspection.getClass()
+                        .getDeclaredMethod("getMinVisibilityLevel", PsiMember.class);
+
+                getMinVisibilityLevel.setAccessible(true);
+
+                level = (int)getMinVisibilityLevel.invoke(myVisibilityInspection, member);
+            } catch (Exception e) {
+                Logger.getInstance(CustomAccessCanBeTightenedInspection.class)
+                        .warn("Failed to invoke myVisibilityInspection", e);
+                throw new IllegalStateException("Failed to invoke myVisibilityInspection", e);
+            }
+
             boolean entryPoint = myDeadCodeInspection.isEntryPoint(member) ||
                     member instanceof PsiField && (UnusedSymbolUtil.isImplicitWrite((PsiVariable)member) || UnusedSymbolUtil.isImplicitRead((PsiVariable)member));
             if (entryPoint && level <= 0) {
@@ -310,9 +325,29 @@ public class CustomAccessCanBeTightenedInspection extends AbstractBaseJavaLocalI
                 // except when used in annotation:
                 // @Ann(value = C.VAL) class C { public static final String VAL = "xx"; }
                 // or in implements/extends clauses
-                if (VisibilityInspection.containsReferenceTo(innerClass.getModifierList(), member) ||
-                        VisibilityInspection.containsReferenceTo(innerClass.getImplementsList(), member) ||
-                        VisibilityInspection.containsReferenceTo(innerClass.getExtendsList(), member)) {
+
+                final BiPredicate<PsiElement, PsiElement> containsReferenceTo;
+                try {
+                    final Method m = VisibilityInspection.class
+                            .getDeclaredMethod("containsReferenceTo", PsiElement.class, PsiElement.class);
+                    m.setAccessible(true);
+
+                    containsReferenceTo = (s, t) -> {
+                        try {
+                            return (boolean) m.invoke(null, s, t);
+                        } catch (Exception e) {
+                            throw new RuntimeException(e);
+                        }
+                    };
+                } catch (final Exception ex) {
+                    LOG.warn("Failed to make VisibilityInspection#containsReferenceTo accessible", ex);
+                    throw new IllegalStateException("Failed to make VisibilityInspection#containsReferenceTo accessible", ex);
+                }
+
+
+                if (containsReferenceTo.test(innerClass.getModifierList(), member) ||
+                        containsReferenceTo.test(innerClass.getImplementsList(), member) ||
+                        containsReferenceTo.test(innerClass.getExtendsList(), member)) {
                     return suggestPackageLocal(member);
                 }