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
请先登录再写评论。
Look's like it planned for Irida already :)
TIA,
Dmitry
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
Thanks :)
Tom
I'm looking forward to any results. Naturally I'm expecting a fantastic
user interface from you;-)
Bas
One more time:
"This refactoring will be present in Irida"!!!
Don't lose you time to already implemented features, look into missing :)
TIA,
Dmitry
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
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
OK, I've got it - need to use EditorAction instead of AnAction.
Tom
Thomas
Time to give the UI designer a chance: try "New -> Dialog".
Alain
That's exactly what I did :)
--
Have a nice weekend!
Tom
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
I'm agree with Dmitry :)
http://www.jetbrains.net/jira/browse/IDEA-42
Thanks!
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
:) 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? :)
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
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!
The type of the variable, hence the left expression.
Should be able to change to
>
Tom
I have the PsiReferenceExpression of 'items' in 'bar(items);'. How to get
the 'Collection'-type of the bar()-declaration?
Tom
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!
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!
You are right, your example contains a get(int), which I've overseen.
Tom
Yes, I have, it helps a lot to browse the structure.
Do I need to get it from the n-th parameter or does the Psi-object itself
contains the necessary type information?
Tom
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
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
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:
Note again that this code was never compiled and may not fulfill its intended purpose.
Bas
Thanks again, that did it :)
Tom
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
Something like following:
PsiMethodCallExpression call = ...;
PsiMethod method = call.resolveMethod();
if (method != null) {
PsiMethod originalMethod = method.findDeepestSuperMethod();
}
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.
First, thanks for the detailled answer.
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
Hi Thomas,
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 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:
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