Type refactoring

Hi,

A long time ago I've asked for a refactoring, that safely can change the
type of a variable according to its usages. Since Jetbrains obviously don't
show interest to implement it, I want to know from those whole already know
the OpenApi well, whether it is open enough to write a plugin myself.

- I need to get the "object" at the cursor position
- if it is no variable, I return
- then I need to find all "usages" to detect the upper-most and lowest type
in the hierarchy
- then I would like to show a dialog box showing all allowed types and let
the user select it

--
Thanks in advance,
Tom

0
51 comments

Look's like it planned for Irida already :)

TIA,
Dmitry

0

I would definitely think it's possible to write such a refactoring yourself. You should probably look at the source of some simple plugins to get a feel for it. And you'll want to install the PsiViewer plugin, which although a little buggy is invaluable to learn the PSI (program structure interface - sort of an abstract syntax tree).

I think you haven't described even half of the things you need to do for such a plugin, but here's how I would start:

Note that I'm not certain this is the best way to do such a thing and I have not even compiled this code yet. It's just something to get you started, cause some things can be hard to find in the openapi.

Good luck!
Bas

0

Thanks :)

Tom

0

I'm looking forward to any results. Naturally I'm expecting a fantastic
user interface from you;-)

Bas

0

One more time:
"This refactoring will be present in Irida"!!!
Don't lose you time to already implemented features, look into missing :)

TIA,
Dmitry

0

Well, the possible classes can be detected now :) Thanks again for your
code, I'm sure, without it I would have given up because of Dmitry's statement.

Now I only need to go back to the roots of Swing to find out how to display
a simple dialog; I don't want to make the plugin 10 times bigger than
necessary because of using SmartCVS' GUI-frameworks.

Tom

0

Hmm, now I'm getting following assertion:

Assertion failed: Write access is allowed inside write-action only (see
com.intellij.openapi.application.Application.runWriteAction())

What's up with Application.runWriteAction(), where can I information about it?

Tom

0

OK, I've got it - need to use EditorAction instead of AnAction.

Tom

0

Thomas

Now I only need to go back to the roots of Swing to find out how to
display a simple dialog;



Time to give the UI designer a chance: try "New -> Dialog".


Alain

0

That's exactly what I did :)

--
Have a nice weekend!
Tom

0

An EditorAction will certainly work. I should of thought of that myself, but I was a bit confused by the name. It seems to be just for actions in the editor, but in fact it's probably much easier to always use EditorAction and not AnAction.

You will probably know this already, but you can also run write actions with something like this.

Bas

0

I'm agree with Dmitry :)
http://www.jetbrains.net/jira/browse/IDEA-42

Thanks!

0

I guess, the mentioned issue is something different. What I mean is
http://www.intellij.net/tracker/idea/viewSCR?publicId=6017 .

No matter, I need it now, not in a couple of months. And it is a good
training for how to create a simple IDEA plugin. I'm sure, sometimes you
also like to play with "new" APIs.

Tom

0

:) Yes, you are right! :)

Good luck!
BTW, looking into JIRA issue and this SCR i saw, that this refactoring may refactor:
1. Type of variable/field.
1.1 Type in usage context.

2. Type of getter/setter
2.1 Type of ussage context
2.2 Type of overrided context
2.3 Type of caused implementation in case of interface implementation.

So, seems to not very simple plugin? :)

0

I just want to change a variable declaration. Example:

public void foo() {
final ArrayList items = new ArrayList();
bar(items);
}

public void bar(Collection collection) {
}

Here you should be able to change the type of the variable 'items', for
example, to Collection, List, AbstractList, ...

Tom

0

Hi,

Left or right type definition? :)
Becouse i'm thinking that changing left type is impossible, and right type is no need to be refactored.

For example:


If you change ArrayList to one of implementation of List - this is not can re Refactoring. You just change it by CtrlShitSpace after 'new' token.

If you will change List, then:
1. Find all usages of variable
2. Calculate by some magic algorithm scope of available types (in this example scope of method poo is larger that scope of method foo, and you must take scope of foo, but also list.get is using, so you can't use Collection, only List and all above)

Now, even you call this as refactor, i still think that it is not pure refactoring. So, can you explain that code you will refactor by plugin?

IFAIK, plugin, about you said - it some smart type sugegsting and scope detection by variable usage. As CtrlShiftSpace after 'new':)

Thanks!

0

Left or right type definition? :)


The type of the variable, hence the left expression.

 void boo() {
>   List list = new ArrayList();
>   Object o = list.get(0);
>   foo(list);
>   poo(list);
> }
> 
> void foo(Collection list) {
>   // ...
> }
> 
> void poo(Object object) {
>   // ...
> }
> ]]>


Should be able to change to

>

 void boo() {
 >   Collection list = new ArrayList();
 >   Object o = list.get(0);
 >   foo(list);
 >   poo(list);
 > }
 >
 > void foo(Collection list) {
 >   // ...
 > }
 >
 > void poo(Object object) {
 >   // ...
 > }
 > ]]>


Tom

0


I have the PsiReferenceExpression of 'items' in 'bar(items);'. How to get
the 'Collection'-type of the bar()-declaration?

Tom

0

Tom,

It can't be Collection, as i understand SRC correctly. The Collection have not method get, but it used in this sample.

I'm wrong?

Thanks!

0

Did you have PsiViewer enabled in IDEA?
AFIAK you will get only PsiIdentifier in this method parameters list. But you have PsiMethodCallExpression, then you can found PsiMethod and get from it PsiParameterList the PsiTypeElement of parameter type.

Thanks!

0

You are right, your example contains a get(int), which I've overseen.

Tom

0

Did you have PsiViewer enabled in IDEA?


Yes, I have, it helps a lot to browse the structure.

AFIAK you will get only PsiIdentifier in this method parameters list. But you have PsiMethodCallExpression, then you can found PsiMethod and get from it PsiParameterList the PsiTypeElement of parameter type.


Do I need to get it from the n-th parameter or does the Psi-object itself
contains the necessary type information?

Tom

0

I don't have IDEA in front of me right now, but calling resolve() on a PsiReferenceExpression returns the object the reference refers to, a PsiMethod in this case. You can query that for further info. Does that help?

Bas

0

Sorry, it does not work. In this example:

resolve() returns a PsiLocalVariable, that's .type() returns List, not
Collection :(

Can somebody from Jetbrains please comment on this issue? Thanks in advance.

Tom

0

Ah sorry, didn't quite understand which reference you had there. Ok, when you have the reference to "coll", you then want the reference to the "doSomethingElse" method in this case. I would do it like this:

 0) {
		final PsiElement parentsParent = parent.getParent();
		if (parentsParent instanceof PsiMethodCallExpression) {
			final PsiMethodCallExpression expression = (PsiMethodCallExpression)parentsParent;
			final PsiReferenceExpression methodReference = expression.getMethodExpression();
			final PsiMethod method = (PsiMethod)methodReference.resolve();
			final PsiParameterList parameterList = method.getParameterList();
			final PsiParameter[] parameters = parameterList.getParameters();
			PsiType type = parameters[index].getType();
		}
	}
}
]]>

Note again that this code was never compiled and may not fulfill its intended purpose.

Bas

0

Thanks again, that did it :)

Tom

0

I now wanna check, in what PsiTypes, the method 'size()' is defined. I have
the PsiMethodCallExpression, which can return the PsiMethod, which can
return the containing PsiClass. In other words, I have a PsiMethod and want
to get all super-types and implemented interfaces, which contain this method
as well.

I've skimmed the IntentionPowerPack-sources but could not find something
similar.

BTW, what is the difference between PsiType, PsiClass and PsiClassType? How
to convert from a PsiClass to a PsiType?
The documentation provided by Jetbrains is very week (or I did not find it);
just got the non-description-version of the OpenAPI-Javadoc.

--
Thanks in advance,
Tom

0

Something like following:

PsiMethodCallExpression call = ...;
PsiMethod method = call.resolveMethod();
if (method != null) {
PsiMethod originalMethod = method.findDeepestSuperMethod();
}

BTW, what is the difference between PsiType, PsiClass and
PsiClassType? How
to convert from a PsiClass to a PsiType?


PsiType may denote types other than reference types like primitive ones (int,
long, etc.)
PsiClassType denotes reference types.

PsiClass->PsiType conversion should be done as follows:
PsiManager.getInstance(project).getElementFactory().createType(psiClass)

PsiClassType->PsiClass conversion should be done as follows:
psiClassType.resolve()
Whether substution of generic parameters is important for you use resolveGenerics()
method instead.

0

First, thanks for the detailled answer.

Something like following:

PsiMethodCallExpression call = ...;
PsiMethod method = call.resolveMethod();
if (method != null) {
PsiMethod originalMethod = method.findDeepestSuperMethod();
}


Unfortunately this does not work for me. I have a couple of possible
variable Psi(Class)Types, which I want to check, whether they contain the
same method. In other words, I need all Psi(Class)Types between (including)
method.getContainingClass() and originalMethod.getContainingClass().

Tom

0

Hi Thomas,

 coll = new ArrayList();
> 	
> System.out.println(coll.size());]]>

I now wanna check, in what PsiTypes, the method
'size()' is defined. I have
the PsiMethodCallExpression, which can return the
PsiMethod, which can
return the containing PsiClass. In other words, I
have a PsiMethod and want
to get all super-types and implemented interfaces,
which contain this method
as well.


You might want to take a look at the com.intellij.psi.util.PsiSuperMethodUtil class. It has some utility methods which may be useful to you.


I've skimmed the IntentionPowerPack-sources but could
not find something
similar.

BTW, what is the difference between PsiType, PsiClass
and PsiClassType? How
to convert from a PsiClass to a PsiType?


I don't know too much about it but PsiClassType is a subclass of PsiType with some extra methods for classes. PsiType also describes primitives. As far as I can tell PsiType and PsiClassType are light weight classes for type checking and PsiClass provides meta information about classes.

To convert from a PsiClass to a PsiType:

The documentation provided by Jetbrains is very week
(or I did not find it);
just got the non-description-version of the
OpenAPI-Javadoc.


Psi documentation is getter better actually:-) It still has a long way to go, but since it has been officially opened documentation has started to appear here and there where there used to be nothing. Existing plugin sources continue to be the best source of information though. Some stuff can also be found on the www.intellij.org wiki, but that's mostly out of date and not structured very well. Alain Ravet had the idea some time ago of building an openapi wiki, but the response was low.

Bas

0

Please sign in to leave a comment.