PsiMethod.findSuperMethods() doesn't include java.lang.Object supermethods

I'm trying to determine if a particular method is canonical (e.g. toString, equals or hashCode). For example,

Then super.toString() refers to java.lang.Object's toString() method.

I believe that

used to return all supermethods of the method, even if they were in java.lang.Object. (The new syntax for Demetra is "method.findSuperMethods()" but it appears to work the same as the old syntax.) So if "method" was the psiMethod for class A's toString() method, an array of one PsiMethod (java.lang.Object's toString method) was returned. But this is no longer happening.

In fact, it appears that now the top level class is no longer java.lang.Object; i.e. given a method in a top-level class like "A" above,

returns null but used to return the PsiClass for java.lang.Object.

I thought all classes were supposed to extend java.lang.Object. Anybody know if this is a bug? Or has the PSI tree design been changed?

Thanks,
-Dave

18 comments

The following test case is OK in Demetra:

public void testJavaLangObjectSuperMethod() throws Exception {
final PsiClass aClass =
getPsiManager().getElementFactory().createClassFromText("public String toString() {return null;}", null);
final PsiMethod method = aClass.getMethods()[0];
final PsiMethod[] superMethods = method.findSuperMethods();
assertEquals(1, superMethods.length);
assertEquals("java.lang.Object", superMethods[0].getContainingClass().getQualifiedName());
}


method.getContainingClass().getContainingClass() always returned null, as it is expected.

0

Eugene Vigdorchik wrote:

The following test case is OK in Demetra:

public void testJavaLangObjectSuperMethod() throws Exception {
final PsiClass aClass =
getPsiManager().getElementFactory().createClassFromText("public String toString() {return null;}", null);
final PsiMethod method = aClass.getMethods()[0];
final PsiMethod[] superMethods = method.findSuperMethods();
assertEquals(1, superMethods.length);
assertEquals("java.lang.Object", superMethods[0].getContainingClass().getQualifiedName());
}


This test case fails on my system on build #5131:

junit.framework.AssertionFailedError: expected: but was:<0>]]>
at com.siyeh.PsiTests.testJavaLangObjectSuperMethod(PsiTests.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.testFramework.IdeaTestCase.access$201(IdeaTestCase.java:64)
at etcetera....

But maybe that is because it is fixed already.

Bas

0

Yep, that's the only explanation that comes to my mind.

0

Eugene Vigdorchik wrote:

Yep, that's the only explanation that comes to my mind.


So, when is the next build going to be released, so I can test this
hypothesis? ;)

Bas

0

Hehe, I'm not sure it is hypothesis checking that drives EAP builds:)

0

Eugene,

Thanks for the reply. I appreciate it.

Something is amiss. Running your test case in both 5.1 and Demetra, no supermethods are returned for me. Can there be something about my environment that can affect this? (I can't imagine what it is; language level or JDK shouldn't affect it). I can try it again in the next build of Demetra if you think that this was a bug that was recently fixed, but I bet nothing will change. :)

Thanks,
-Dave

0

It won't be fair to accept your bid, will it?:) I indeed made a small refactoring in the upcoming build, but I'm not sure it is it.

0

Hehe, of course, you could try the test code on 5.1 or previous release of Demetra -- then you would know if you should accept the bet!

I will bet a nice bottle of alcohol-free vodka.. (actually, just bottled water -- looks and tastes almost the same!)

Seriously, I'll try out the next release of Demetra when available.

-Dave

0

Bad news, your test case still fails for me on build #5162.

but was:<0> at com.siyeh.psi.PsiTest.testJavaLangObjectSuperMethod(PsiTest.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.testFramework.LightIdeaTestCase.b(LightIdeaTestCase.java:116) at com.intellij.testFramework.LightIdeaTestCase.access$500(LightIdeaTestCase.java:118) at com.intellij.testFramework.LightIdeaTestCase$5.run(LightIdeaTestCase.java:16) ]]>

Bas

0

I think this is caused by something I do. The test doesn't have a jdk
and I don't know how to give it one.

Bas

Bas Leijdekkers wrote:

Bad news, your test case still fails for me on build #5162.

junit.framework.AssertionFailedError: expected:<1> but was:<0> > at com.siyeh.psi.PsiTest.testJavaLangObjectSuperMethod(PsiTest.java:23) > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) > at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) > at com.intellij.testFramework.LightIdeaTestCase.b(LightIdeaTestCase.java:116) > at com.intellij.testFramework.LightIdeaTestCase.access$500(LightIdeaTestCase.java:118) > at com.intellij.testFramework.LightIdeaTestCase$5.run(LightIdeaTestCase.java:16) > ]]>

Bas

0

Hi Bas,

Yes, something must be different; but I wouldn't think that a missing JDK would be the problem. If your test can run, there must be a java.lang.Object class accessible. The PSI tree ought to be able to locate that class and its methods and complete its supermethod hierarchy properly.

In any case, when the Rearranger plugin runs, it is not finding these supermethods either (any more -- I believe it used to pre-5.0). I can't imagine what might have changed in its environment to cause this.

-Dave

0

To check if jdk is set up, you could try to find a class:
psiManager.findClass("java.lang.Object", yourScope)

Also scope is important, and this could be the reason for the problem.

0

Eugene,

Can you explain what you mean that "scope is important, and this could be the reason for the problem"? In your sample JUnit code to find supermethods, there is no scope parameter. Is there some default scope, affected by environment, that could be causing Bas' and my tests to fail?

I am also confused by your suggestion to see if a JDK is set up. It seems to me that PsiManager.findClass("java.lang.Object",..) would find that class regardless of presence of a JDK. There has to be a java.lang.Object class for anything to run, no?

Thanks very much,
-Dave

0

Hey Dave,

I realized something was wrong with my test case when I remembered findSuperMethods() is used all over the place in InspectionGadgets and there are no problems with those inspections. It looked like the psi couldn't find the superclass (java.lang.Object) of my test class. I have now discovered a way to give an IdeaTestCase a jdk to use for the psi tests and Eugene's test works perfectly for me now. I'll post the source to it if you'd like...
Anyway, I really hope you find a way to get Rearranger working for Demetra. It one of the reasons I still use 5.1 often, I miss it.

Bas

0

Hi Bas,

Maybe you can explain this further. I'm confused by the need for a JDK at all. Why should the PSI tree not be able to find java.lang.Object, or mark it as the superclass of every other class, without a JDK?

First, java.lang.Object is by definition present in every execution of a Java program.

Second, the users who are reporting this to me are not running a JUnit test or an IdeaTestCase. Even if I were able to fix my JUnit test, it would not (necessarily) help the average Rearranger user who may or may not have a particular JDK set up.

Third, I am running with a JDK, and have also tried my JUnit test with the IDEA plugin SDK; the test fails in both cases.

So, yes, I am curious to see what you did in order to make it work. As I say, I have seen this work in Rearranger in the past (and maybe it would work even in the present if I knew what to change in the environment). But it doesn't seem reasonable that the PSI tree would sometimes find java.lang.Object, and sometimes not, under any circumstances.

Thanks very much. By the way, I just have to recompile it for Demetra and release it; this bug really isn't preventing the bulk of Rearranger from working.

Regards,
-Dave

0

As far as I understand it, the psi internally uses a jdk to parse against. This may be another jdk than the one its running on (to be able to parse jdk 1.1 code for example). This jdk needs to be specified explicitly.

You could say any jdk has a java.lang.Object so why does the psi need a jdk for that? In theory however, different jdks can have slightly different versions of the Object class and IDEA should be able to work with any of them. Without a jdk the psi doesn't know which version of the Object class is needed.

Here's how I got Eugene's test case to run. First the code:


The getProjectJDK() tells the psi which jdk to parse against. This I can run with the following vm parameters:

-ea
to enable assertions. IDEA should really enable assertions by default for unit tests and plugin run configurations.

-Didea.plugins.load=false
to not load plugins. If not specified every jar of every plugin must be added to the class path to get the test to run.

"-Didea.config.path=C:\Program Files\IDEA_Demetra\sandbox\config"
"-Didea.system.path=C:\Program Files\IDEA_Demetra\sandbox\system"
path to the sandbox to run in, because it's a plugin test.

And I also specify the working directory to be the bin directory of my IDEA installation to prevent log file complaints: C:\Program Files\IDEA_Demetra\bin

Bas

0

Bas,

Thanks! Adding the getProjectJDK() method (actually overriding the getProjectJDK() method from LightCodeInsightTestCase) did the trick; Eugene's test runs successfully now.

But what does this mean for the Rearranger plugin? I am still confused why findSuperMethods() doesn't work in that environment. There's no ...TestCase class when the plugin is running, so I'm not sure how I even could supply a JDK. It seems to me that the user has already specified a project JDK in the project configuration, and I have no business overriding it. Yet it would also seem that no JDK is in place, since that's the behavior I'm observing. Is there a way to obtain the project JDK that PSI is using? I didn't see anything in ProjectManager.getInstance().getDefaultProject() or in ProjectJdkTable that would return a project's JDK.

I also wonder what the supermethod LightCodeInsightTestCase.getProjectJDK() did. It seems that by default you would want to use the JDK returned by ProjectJdkTable's getInternalJDK(), if no other JDK was specified.

And it is strange: doesn't it seem buggy to you that the PSI tree may or may not include java.lang.Object as the superclass of all other classes depending on whether a JDK is specified, even when an internal JDK is always available?

Thanks for all your help.
-Dave

0

For IDEA itself (not for tests) I can imagine 2 reasons for indSuperMethods() not work as expected. First method itself could be invalid (check if isValid() returns true), second method might be from the module where jdk is not configured (no, we don't have any internal jdk substituting the one configured in Modules dialog)

If these ideas do not help, then you could probably post the code extract from your plugin?

0

Please sign in to leave a comment.