How to let a PsiClass implement an interface that extends another interface

Hi,

I'm writing some unit tests for a plugin I'm writing. For the test I want to have a class X that implements an interface Y which in turn extends interface Z. Below is the code I use to create the PsiClasses only they're not related yet.

PsiElementFactory psiElementFactory = getPsiManager().getElementFactory();

PsiJavaFile interfaceZ = (PsiJavaFile) psiElementFactory.createFileFromText("Z.java",
"package p1.p2;\n" +
"\n" +
"public interface Z {\n" +
" public void a(int one, long two);\n" +
" public void b();\n" +
"}");

PsiJavaFile interfaceY = (PsiJavaFile) psiElementFactory.createFileFromText("Y.java",
"package p1.p2;\n" +
"\n" +
"public interface Y extends Z {\n" +
" public void c();\n" +
" public void d();\n" +
"}");

PsiJavaFile classX = (PsiJavaFile) psiElementFactory.createFileFromText("X.java",
"package p1.p2;\n" +
"\n" +
"public class X implements Y {\n" +
" public void a() { }\n" +
" public void b() { }\n" +
" public void c() { }\n" +
" public void d() { }\n" +
"}");

According to the PsiViewer, the PsiClass for interface Y should have a PsiReferenceList containing:

- PsiJavaToken: extends
- PsiWhiteSpace
- PsiJavaCodeReferenceElement:X which in its turn contains:
- PsiJavaToken: X

But when trying to set this up for PsiClass representing interface Y with the code below, the last line fails with: java.lang.ClassCastException: com.intellij.psi.impl.light.LightKeyword...

PsiJavaToken extendsToken = psiElementFactory.createKeyword("extends");
PsiWhiteSpace psiWhiteSpace = (PsiWhiteSpace) psiElementFactory.createWhiteSpaceFromText(" ");
PsiJavaCodeReferenceElement referenceElement = psiElementFactory.createClassReferenceElement(interfaceZ.getClasses()[0]);

PsiReferenceList psiReference = psiElementFactory.createReferenceList(
new PsiJavaCodeReferenceElement[] {
(PsiJavaCodeReferenceElement) extendsToken,
(PsiJavaCodeReferenceElement) psiWhiteSpace,
referenceElement});

My question is how to setup the Psi structure correctly that all three PsiClass are correctly related to each other?

BTW, I used this approach because although I already have the actual java source files which define the class and the two interfaces, I was not able to use these java sources within the test method of a IdeaTestCase class...

Thanks in advance,

Raymond Brandon

4 comments
Comment actions Permalink

Hello Raymond,

RB> I'm writing some unit tests for a plugin I'm writing. For the test I
RB> want to have a class X that implements an interface Y which in turn
RB> extends interface Z. Below is the code I use to create the
RB> PsiClasses only they're not related yet.
RB>
RB> PsiElementFactory psiElementFactory =
RB> getPsiManager().getElementFactory();
RB>
RB> PsiJavaFile interfaceZ = (PsiJavaFile)
RB> psiElementFactory.createFileFromText("Z.java",
RB> "package p1.p2;\n" +
RB> "\n" +
RB> "public interface Z {\n" +
RB> " public void a(int one, long two);\n" +
RB> " public void b();\n" +
RB> "}");
RB> PsiJavaFile interfaceY = (PsiJavaFile)
RB> psiElementFactory.createFileFromText("Y.java",
RB> "package p1.p2;\n" +
RB> "\n" +
RB> "public interface Y extends Z {\n" +
RB> " public void c();\n" +
RB> " public void d();\n" +
RB> "}");
RB> PsiJavaFile classX = (PsiJavaFile)
RB> psiElementFactory.createFileFromText("X.java",
RB> "package p1.p2;\n" +
RB> "\n" +
RB> "public class X implements Y {\n" +
RB> " public void a() { }\n" +
RB> " public void b() { }\n" +
RB> " public void c() { }\n" +
RB> " public void d() { }\n" +
RB> "}");
RB> According to the PsiViewer, the PsiClass for interface Y should have
RB> a PsiReferenceList containing:
RB>
RB> - PsiJavaToken: extends
RB> - PsiWhiteSpace
RB> - PsiJavaCodeReferenceElement:X which in its turn contains:
RB> - PsiJavaToken: X
RB> But when trying to set this up for PsiClass representing interface Y
RB> with the code below, the last line fails with:
RB> java.lang.ClassCastException:
RB> com.intellij.psi.impl.light.LightKeyword...
RB>
RB> PsiJavaToken extendsToken =
RB> psiElementFactory.createKeyword("extends");
RB>
RB> PsiWhiteSpace psiWhiteSpace = (PsiWhiteSpace)
RB> psiElementFactory.createWhiteSpaceFromText(" ");
RB>
RB> PsiJavaCodeReferenceElement referenceElement =
RB> psiElementFactory.createClassReferenceElement(interfaceZ.getClasses(
RB> )[0]);
RB>
RB> PsiReferenceList psiReference =
RB> psiElementFactory.createReferenceList(
RB> new PsiJavaCodeReferenceElement[] {
RB> (PsiJavaCodeReferenceElement) extendsToken,
RB> (PsiJavaCodeReferenceElement) psiWhiteSpace,
RB> referenceElement});
RB> My question is how to setup the Psi structure correctly that all
RB> three PsiClass are correctly related to each other?

You only need to add the reference element to the reference list. The PSI
implementation will take care of "extends" and whitespace.

--
Dmitry Jemerov
Software Developer
http://www.jetbrains.com/
"Develop with Pleasure!"


0
Comment actions Permalink

Hi Dimitry,

Ok, but when I create the reference list and add it to the psiclass, the actual psiReferenceImpl field still is null after executing the following code:

PsiJavaCodeReferenceElement referenceElement1 = psiElementFactory.createClassReferenceElement(interfaceZ.getClasses()[0]);
PsiReferenceList psiReference1 = psiElementFactory.createReferenceList(
new PsiJavaCodeReferenceElement[] );
interfaceY.add(psiReference1);

assertNotNull(interfaceY.getReference());

Thanks,

Raymond

0
Comment actions Permalink

Hello Raymond,

RB> Ok, but when I create the reference list and add it to the psiclass,
RB> the actual psiReferenceImpl field still is null after executing the
RB> following code:
RB>
RB> PsiJavaCodeReferenceElement referenceElement1 =
RB> psiElementFactory.createClassReferenceElement(interfaceZ.getClasses(
RB> )[0]);
RB> PsiReferenceList psiReference1 =
RB> psiElementFactory.createReferenceList(
RB> new PsiJavaCodeReferenceElement[]
RB> );
RB> interfaceY.add(psiReference1);
RB> assertNotNull(interfaceY.getReference());

interfaceY.getExtendsList().add(psiReference1);

Also, what do you expect the getReference() method to return? It will not
return anything when you call it on an entire interface. getReference() makes
sense for individual nodes in the PSI tree (identifiers, for example), and
not for something like an interface which has lots of child nodes.

--
Dmitry Jemerov
Software Developer
http://www.jetbrains.com/
"Develop with Pleasure!"


0
Comment actions Permalink

Thanks Dimitry I got it working now!

Raymond

0

Please sign in to leave a comment.