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

51 comments

You might want to take a look at the com.intellij.psi.util.PsiSuperMethodUtil class.


That's what I was looking for. As always, thanks :)

Tom

0

How to place an action in the Refactor menu? Where I can find all the
constants for the menus?

Tom

0

Hi Tom,

I guess I can answer one more time:-)

Thomas Singer (MoTJ) wrote:

How to place an action in the Refactor menu?


The easiest option is to specify your action in plugin.xml:

  
    
    
  

]]>

You can also add it programmatically:

Where I can find all the
constants for the menus?


There basically impossible to find these days. IDEA used to come with some small plugin examples and documentation. I think it's not there anymore since somewhere at the start of the Pallada EAP. I have attached the files in a zip to this message. Look in ActionManager.xml for all action constants.

Bas



Attachment(s):
openapi_examples.zip
0

<actions>
<group>
<action text="_Change Type" id="change_type"/>
<add-to-group group-id="RefactoringMenu" anchor="after" relative-to-action="ChangeSignature" />
</group>
</actions>


Thanks again, I've tried with "RefactorMenu" without success.

Look in ActionManager.xml for all action constants.


Ah, that's what I was looking for.

Tom

0

It's getting more complicated. Imagine following code snippet:

Then it is not possible to replace the type of the local variable 'coll'
from Collection to List, because it would resolve to a different method.

How to check, whether 'doSomethingElse(List, int)' will resolve to
'doSomethingElse(Collection, int)'?

Tom

0

Who wants to try it out, may get the source code from:
root : :pserver:guest@dev.java.net:/shared/data/ccvs/repository
password: empty
path : intellij-idea-plugins/TypeRefactoring

But don't expect too much, it is very limited in functionality at the moment.

Tom

0

I guess, just find them in current class/suppers/interfaces.
This is not referencable items in call context, i suppose.
But, looking on Ctrl+Space completion, i think, that some easy way presented... Maybe some one from JB help?

0

Thats not quite simple indeed. The basic idea would be to create a copy of
the variable and context (method call) it is being resolved from and check
whether new method call still resolves to the same method. Something like
following:

PsiElementFactory factory = PsiManager.getInstance(project).getElementFactory();
PsiCodeBlock newBlock = factory.createCodeBlockFromText("{Collection col;
doSomethingElse(coll, 1);}");
PsiVariable newVariable = (PsiVariable)((PsiDeclarationStatement)newBlock.getStatements()[0]).getDeclaredElements()[0];
newVariable.getTypeElement().replace(factory.createTypeElement(newType));
PsiMethodCallExpression newCall =(PsiMethodCallExpression)((PsiExpressionStatement)newBlock.getStatements()[1]).getExpression();

if (newCall.resolveMethod().equals(oldCall.resolveMethod)) {
// OK
}
else {
// FAIL
}


The code is surely simplified from what it should actually be.
Another idea would be to copy the whole code block the variable to be changed
is located at and verify every method call out there in one pass.


Cheers,
Max

0

Hmm, although an interesting approach, I guess it will not work. Take this
example:

Now I'm sure,

PsiCodeBlock newBlock = factory.createCodeBlockFromText("{Collection col;
doSomethingElse(coll, 1, ao);}");

would not resolve to any method, because ao is not know...

It looks like I need to create a whole method call and replace all 'coll'
occurences programatically :( How do you do that in "Use Interface Where
Possible"?

Tom

0

Hmm, although an interesting approach, I guess it will not work.

Not that bad actually. I've missed some important point in my code:
PsiCodeBlock newBlock = factory.createCodeBlockFromText("{Collection col;
doSomethingElse(coll, 1);}", context);

createCodeBlock... method has extra parameter (PsiElement context) which
is a context for all references of the created codeblock to be resolved in
case the cannot be resolved by the block itself. That could be an original
code method invocation in your case.

0

Thank you very much, it seems to work fine now :]

Tom

0

I've found a use case, where this does not work: when you are using
member variables, which are referenced with a "this."-prefix. Example:

{ java.lang.Double this.value;
methodCall(this.value); }

Do you have another idea, how to handle such cases? Thanks in advance.

Tom

0

Maxim, do you also have a good idea for these fields? Thanks in advance.

Tom

0

Thomas Singer (MoTJ) wrote:

I've found a use case, where this does not work: when you are using
member variables, which are referenced with a "this."-prefix. Example:

{ java.lang.Double this.value;
methodCall(this.value); }

Do you have another idea, how to handle such cases? Thanks in advance.

Tom


Without knowing the specifics I guess you should replace the actual method
parameter you're gonna change with a dummy of the specific type.

Something like

{ Double __dummy; methodCall(__dummy); }

or even simpler

{ methodCall((Double)null); }

Since you're only interested if the method that resolves from the call is the
same as the original one that should work, shouldn't it?

Sascha

0

Sorry, I missed the point where the problem is and what is an activity you're
searching an API or pattern to perform?

Maxim, do you also have a good idea for these fields? Thanks in
advance.

Tom



0

The problem is, that your suggested pattern only works for local
variables, but not so for fields. For a local variable one can write:
{ java.util.Collection coll; foo(coll); }
For a (with "this."-prefixed) field you cannot write:
{ java.util.Collection this.field; foo(this.field); }

And, I have no idea, how to replace the reference to this.field in the
temporary code-block with something else, e.g. this_field. Because it
might happen, that - when there is no local variable, the method call
might look like:
{ java.util.Collection this.field; foo(this.field, bar(field)); }
Both, this.field and field, reference the same field.

Tom

0

Tom,

in case you're still interested, I've attached something very quickly hacked
that I believe solves the problem. Lacks a lot of sanity checks, but seems to do
what it is supposed to. Attached is the whole class, but the most changes are in
the method isAssignableToMethodCall().

I hope it helps a little.

Sascha
package de.regnis.tr;

import com.intellij.openapi.actionSystem.DataConstants;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.util.PsiSuperMethodUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;

import java.util.*;

/**

  • @author Thomas Singer

*/
final class TypeRefactoringWriteActionHandler extends EditorWriteActionHandler {

// Constants ==============================================================

private static final Logger LOG = Logger.getInstance("plugin.typeRefactoring");

// Implemented ============================================================

public void executeWriteAction(Editor editor, DataContext dataContext) {
final Project project = (Project)dataContext.getData(DataConstants.PROJECT);
final PsiManager manager = PsiManager.getInstance(project);
final PsiElement element = getElementAtCaret(editor, dataContext);
if (element == null) {
return;
}

final PsiVariable variable = getVariable(element);
if (variable == null) {
Messages.showWarningDialog("You need to select a variable.", TypeRefactoringBundle.dlg_title());
return;
}

try {
if (!checkVariable(variable)) {
return;
}

final List allowedTypes = getAllowedTypes(variable, manager.getSearchHelper());

if (allowedTypes.size() < 2) {
Messages.showWarningDialog(TypeRefactoringBundle.dlg_msg_noAlternativesFound(), TypeRefactoringBundle.dlg_title());
return;
}

final PsiClassType newType = chooseTypeByUser(allowedTypes, variable, project);
if (newType == null) {
return;
}

replaceVariableType(newType, variable, manager.getElementFactory());
}
catch (AbortException ex) {
LOG.info("Aborting", ex);
Messages.showErrorDialog("Don't know what to do. Details: " + ex.getMessage(), TypeRefactoringBundle.dlg_title());
return;
}
}

// Utils ==================================================================

private PsiElement getElementAtCaret(Editor editor, DataContext dataContext) {
final Project project = (Project)dataContext.getData(DataConstants.PROJECT);
final Document document = editor.getDocument();
final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (!file.isValid() || !file.isWritable()) {
return null;
}

final CaretModel caretModel = editor.getCaretModel();
return file.findElementAt(caretModel.getOffset());
}

private PsiVariable getVariable(PsiElement element) {
if (!(element instanceof PsiJavaToken)) {
return null;
}

final PsiJavaToken token = (PsiJavaToken)element;
final PsiElement parent = token.getParent();
if (parent instanceof PsiVariable) {
return (PsiVariable)parent;
}

if (parent instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)parent;
final PsiElement resolvedReference = referenceExpression.resolve();
if (resolvedReference instanceof PsiVariable) {
return (PsiVariable)resolvedReference;
}
}

if (parent instanceof PsiJavaCodeReferenceElement) {
final PsiJavaCodeReferenceElement javaCodeReferenceElement = (PsiJavaCodeReferenceElement)parent;
return (PsiVariable)PsiTreeUtil.getParentOfType(javaCodeReferenceElement, PsiVariable.class);
}
return null;
}

private boolean checkVariable(PsiVariable variable) throws AbortException {
if (variable instanceof PsiParameter) {
Messages.showWarningDialog("Changing the type of method parameters is not supported.", TypeRefactoringBundle.dlg_title());
return false;
}

final PsiType type = variable.getType();
if (type instanceof PsiPrimitiveType) {
Messages.showWarningDialog("Changing the type of primitives is not supported.", TypeRefactoringBundle.dlg_title());
return false;
}

if (type instanceof PsiArrayType) {
Messages.showWarningDialog("Changing the type of arrays is not supported.", TypeRefactoringBundle.dlg_title());
return false;
}

if (!(type instanceof PsiClassType)) {
throw new AbortException("Unknown variable type " + type);
}

final PsiElement parent = variable.getParent();
if (parent instanceof PsiDeclarationStatement) {
return true;
}
else if (variable instanceof PsiField) {
return true;
}
else {
return false;
}
}

private List getAllowedTypes(PsiVariable variable, PsiSearchHelper searchHelper) throws AbortException {
final PsiReference[] references = searchHelper.findReferences(variable, variable.getUseScope(), false);

List possibleVariableTypes = null;
for (Iterator it = getAssignmentTypes(references, variable).iterator(); it.hasNext();) {
final PsiClassType type = (PsiClassType)it.next();
if (possibleVariableTypes == null) {
possibleVariableTypes = new ArrayList();
possibleVariableTypes.add(type);
getSuperTypes(type, possibleVariableTypes);
}
else {
removeUnassignableTypes(type, possibleVariableTypes);
}
}

if (possibleVariableTypes == null) {
return Collections.EMPTY_LIST;
}

logTypes("Possible variable types according to assignments", possibleVariableTypes);

keepOnlyRequiredUsageTypes(references, possibleVariableTypes);

logTypes("Possible variable types", possibleVariableTypes);

return possibleVariableTypes;
}

private void removeUnassignableTypes(PsiClassType assignmentType, Collection possibleVariableTypes) {
for (Iterator it = possibleVariableTypes.iterator(); it.hasNext();) {
final PsiClassType possibleVariableType = (PsiClassType)it.next();
if (!possibleVariableType.isAssignableFrom(assignmentType)) {
it.remove();
}
}
}

private Collection getAssignmentTypes(PsiReference[] references, PsiVariable variable) throws AbortException {
final Collection types = new ArrayList();

final PsiExpression initializer = variable.getInitializer();
if (initializer != null) {
final PsiClassType initializerType = getClassTypeNotNull(initializer.getType());
if (!TypeConversionUtil.isNullType(initializerType)) {
types.add(initializerType);
}
}

for (int i = 0; i < references.length; i++) {
final PsiReference reference = references+;
if (!(reference instanceof PsiReferenceExpression)) {
continue;
}

final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)reference;
final PsiElement parent = referenceExpression.getParent();
if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
final PsiExpression rightExpression = assignmentExpression.getRExpression();
if (rightExpression == null) {
throw new AbortException("Expected a right expression in '" + assignmentExpression.getText() + "'");
}

final PsiClassType type = getClassType(rightExpression.getType());
if (type == null) {
continue;
}

if (!types.contains(type)) {
types.add(type);
}
}
}
return types;
}

private void keepOnlyRequiredUsageTypes(PsiReference[] references, Collection possibleVariableTypes) throws AbortException {
for (int i = 0; i < references.length; i++) {
final PsiReference reference = references+;
if (!(reference instanceof PsiReferenceExpression)) {
continue;
}

final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)reference;
final PsiElement parent = referenceExpression.getParent();
// ignore assignments
if (parent instanceof PsiAssignmentExpression) {
continue;
}

keepAllowedTypes(referenceExpression, parent, possibleVariableTypes, referenceExpression.getText());
}
}

private void keepAllowedTypes(PsiExpression expression, PsiElement parent, Collection possibleVariableTypes, String variableName) throws AbortException {
if (parent instanceof PsiExpressionList) {
final PsiExpressionList expressionList = (PsiExpressionList)parent;
final int index = getMethodCallParameterIndex(expression, expressionList);
if (index < 0) {
throw new AbortException("No matching method parameter found.");
}

final PsiElement expressionListParent = expressionList.getParent();
if (expressionListParent instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expressionListParent;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) {
throw new AbortException("Method could not be resolved.");
}

keepAssignableToCall(method, methodCallExpression, variableName, index, possibleVariableTypes);
}
else if (expressionListParent instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)expressionListParent;
final PsiMethod method = newExpression.resolveConstructor();
if (method == null) {
throw new AbortException("Constructor could not be resolved.");
}

keepAssignableToCall(method, newExpression, variableName, index, possibleVariableTypes);
}
else {
throw new AbortException("Unexpected element " + expressionListParent);
}
}
else if (parent instanceof PsiReturnStatement) {
final PsiReturnStatement returnStatement = (PsiReturnStatement)parent;
final PsiMethod method = (PsiMethod)PsiTreeUtil.getParentOfType(returnStatement, PsiMethod.class);
if (method != null) {
final PsiClassType returnType = getClassTypeNotNull(method.getReturnType());
keepOnlyTypesAssignableTo(returnType, possibleVariableTypes);
}
}
else if (parent instanceof PsiLocalVariable) {
final PsiLocalVariable localVariable = (PsiLocalVariable)parent;
keepOnlyTypesAssignableTo(getClassTypeNotNull(localVariable.getType()), possibleVariableTypes);
}
else if (parent instanceof PsiConditionalExpression) {
final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)parent;
final PsiElement parent2 = conditionalExpression.getParent();
keepAllowedTypes(conditionalExpression, parent2, possibleVariableTypes, variableName);
}
else if (parent instanceof PsiParenthesizedExpression) {
final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)parent;
final PsiElement parent2 = parenthesizedExpression.getParent();
keepAllowedTypes(parenthesizedExpression, parent2, possibleVariableTypes, variableName);
}
else if (parent instanceof PsiTypeCastExpression) {
final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)parent;
final PsiTypeElement castTypeElement = typeCastExpression.getCastType();
if (castTypeElement == null) {
throw new AbortException("Cast type undefined.");
}

final PsiClassType castType = getClassTypeNotNull(castTypeElement.getType());
for (Iterator it = possibleVariableTypes.iterator(); it.hasNext();) {
final PsiClassType possibleVariableType = (PsiClassType)it.next();
if (!castType.isConvertibleFrom(possibleVariableType)) {
it.remove();
}
}
}
else if (parent instanceof PsiBinaryExpression) {
final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent;
final PsiExpression otherExpression = getOtherExpression(expression, binaryExpression);

/* final PsiClassType otherExpressionType = (PsiClassType)otherExpression.getType();
if (otherExpressionType == null || TypeConversionUtil.isNullType(otherExpressionType)) {
continue;
}
*/
// TODO: rethink it
// Example:
// private Collection coll;
// ...
// if (coll == null) {}
// or
// if (coll == new LinkedList()) {}
// but not
// if (coll == "hello") {}
}
else {
final PsiElement parent2 = parent.getParent();
if (!(parent2 instanceof PsiMethodCallExpression)) {
throw new AbortException("MethodCallExpression expected, got " + parent2);
}

final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)parent2;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) {
throw new AbortException("Method could not be resolved.");
}

final Collection allowedTypes = getAllowedTypes(method);
for (Iterator it = possibleVariableTypes.iterator(); it.hasNext();) {
final PsiClassType possibleVariableType = (PsiClassType)it.next();
if (!assignableTo(possibleVariableType, allowedTypes)) {
it.remove();
}
}
}
}

private void keepAssignableToCall(PsiMethod method, PsiCallExpression callExpression, String variableName, int index, Collection possibleVariableTypes) throws AbortException {
final PsiElementFactory elementFactory = method.getManager().getElementFactory();
final PsiClassType type = getMethodParameterType(index, method);
for (Iterator it = possibleVariableTypes.iterator(); it.hasNext();) {
final PsiClassType possibleVariableType = (PsiClassType)it.next();
if (!isAssignableToMethodCall(possibleVariableType, type, callExpression, method, elementFactory, index)) {
it.remove();
}
}
}

private static PsiClassType getClassType(PsiType type) throws AbortException {
if (type == null || TypeConversionUtil.isNullType(type)) {
return null;
}

if (!(type instanceof PsiClassType)) {
throw new AbortException("Expected class type, not " + type.getPresentableText());
}

final PsiClassType classType = (PsiClassType)type;
if (classType.resolve() == null) {
throw new AbortException("Unknown class type " + classType.getPresentableText());
}
return classType;
}

private static PsiClassType getClassTypeNotNull(PsiType type) throws AbortException {
final PsiClassType classType = getClassType(type);
if (classType == null) {
throw new AbortException("Expected a class type.");
}

return classType;
}

private void keepOnlyTypesAssignableTo(PsiClassType typeToAssign, Collection possibleVariableTypes) {
if (typeToAssign == null) {
return;
}

for (Iterator it = possibleVariableTypes.iterator(); it.hasNext();) {
final PsiClassType possibleVariableType = (PsiClassType)it.next();
if (!typeToAssign.isAssignableFrom(possibleVariableType)) {
it.remove();
}
}
}

private PsiExpression getOtherExpression(PsiExpression expression, PsiBinaryExpression binaryExpression) throws AbortException {
final PsiExpression leftExpression = binaryExpression.getLOperand();
if (leftExpression == expression) {
return binaryExpression.getROperand();
}

final PsiExpression rightExpression = binaryExpression.getROperand();
if (rightExpression == expression) {
return binaryExpression.getLOperand();
}

throw new AbortException("Other expression not found");
}

private boolean isAssignableToMethodCall(PsiClassType possibleVariableType, PsiClassType variableType, PsiCallExpression callExpression, PsiMethod method, PsiElementFactory elementFactory, int index) throws AbortException {
if (!variableType.isAssignableFrom(possibleVariableType)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Removing " + possibleVariableType + " because it is not assignable to " + variableType);
}

return false;
}

final StringBuffer methodCall = new StringBuffer(callExpression.getText().length());
methodCall.append(getMethodToCall(callExpression));
methodCall.append("(");
final PsiExpression[] expressions = callExpression.getArgumentList().getExpressions();
for (int i = 0; i < expressions.length; i++) {
PsiExpression expression = expressions+;
if (i > 0) methodCall.append(", ");
if (i != index) {
methodCall.append(expression.getText());
// methodCall.append("(" + expression.getType().getCanonicalText() + ")" + defaultValue(expression.getType()));
} else {
methodCall.append("(").append(possibleVariableType.getCanonicalText()).append(")").append(defaultValue(possibleVariableType));
}
}
methodCall.append(")");
System.out.println("method = " + methodCall);

final String testMethodCallText = "{" + methodCall + ";}";
final PsiMethod testResolvedMethod = createMethodCallExpression(testMethodCallText, callExpression, elementFactory);
if (!method.equals(testResolvedMethod)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Removing " + possibleVariableType + " because it would resolve to a different method " + testResolvedMethod);
}

return false;
}

return true;
}

private String getMethodToCall(PsiCallExpression callExpression) {
if (callExpression instanceof PsiMethodCallExpression) {
return PsiTreeUtil.getChildOfType(callExpression, PsiReferenceExpression.class).getText();
} else if (callExpression instanceof PsiNewExpression) {
return "new " + PsiTreeUtil.getChildOfType(callExpression, PsiJavaCodeReferenceElement.class).getText();
} else {
return null;
}
}

private String defaultValue(PsiType type) {
if (type instanceof PsiPrimitiveType) {
final String text = type.getCanonicalText();
if ("boolean".equals(text)) {
return "false";
} else if ("char".equals(text)) {
return "'0'";
} else {
return "0";
}
} else {
return "null";
}
}

private PsiMethod createMethodCallExpression(String methodCallText, PsiElement context, PsiElementFactory elementFactory) throws AbortException {
final PsiCodeBlock codeBlock;
try {
codeBlock = elementFactory.createCodeBlockFromText(methodCallText, context);
}
catch (IncorrectOperationException ex) {
throw new AbortException("Incorrect Operation: " + methodCallText, ex);
}

final PsiStatement[] statements = codeBlock.getStatements();
// if (statements == null || statements.length != 2) {
// throw new AbortException("Two statements expected in " + methodCallText);
// }
//
// if (!(statements[1] instanceof PsiExpressionStatement)) {
// throw new AbortException("Expression statement expected in " + statements[1]);
// }
//
final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statements[0];
final PsiExpression expression = expressionStatement.getExpression();
// if (!(expression instanceof PsiCallExpression)) {
// throw new AbortException("Expression expected in " + expressionStatement);
// }
//
final PsiCallExpression callExpression = (PsiCallExpression)expression;
final PsiMethod method = callExpression.resolveMethod();

if (method == null) {
throw new AbortException("Could not resolve method/constructor call " + callExpression.getText());
}

return method;
}

private boolean assignableTo(PsiClassType possibleVariableType, Collection allowedTypes) {
for (Iterator it = allowedTypes.iterator(); it.hasNext();) {
final PsiClassType allowedType = (PsiClassType)it.next();
if (allowedType.isAssignableFrom(possibleVariableType)) {
return true;
}
}
return false;
}

private Collection getAllowedTypes(PsiMethod method) {
final Collection allowedTypes = new ArrayList();

final PsiClassType methodCallType = getType(method);
allowedTypes.add(methodCallType);

final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method);
for (int i = 0; i < superMethods.length; i++) {
final PsiMethod superMethod = superMethods+;
final PsiClassType superType = getType(superMethod);
allowedTypes.add(superType);
}

return allowedTypes;
}

private PsiClassType getType(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass();
final PsiElementFactory elementFactory = containingClass.getManager().getElementFactory();
return elementFactory.createType(containingClass);
}

private int getMethodCallParameterIndex(PsiExpression expression, PsiExpressionList expressionList) {
final PsiExpression[] expressions = expressionList.getExpressions();
for (int i = 0; i < expressions.length; i++) {
if (expressions+ == expression) {
return i;
}
}
return -1;
}

private PsiClassType getMethodParameterType(int parameterIndex, PsiMethod method) throws AbortException {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length + 1 < parameterIndex) {
throw new AbortException("Method has too few arguments.");
}

return getClassTypeNotNull(parameters[parameterIndex].getType());
}

private void logTypes(String text, Collection possibleVariableTypes) {
if (!LOG.isDebugEnabled()) {
return;
}

LOG.debug(text);

for (Iterator it = possibleVariableTypes.iterator(); it.hasNext();) {
final PsiClassType possibleVariableType = (PsiClassType)it.next();
LOG.debug(" " + possibleVariableType.getCanonicalText());
}
}

private void getSuperTypes(PsiClassType type, Collection superTypes) throws AbortException {
final PsiType[] superTypesArray = type.getSuperTypes();
for (int j = 0; j < superTypesArray.length; j++) {
final PsiClassType superType = getClassTypeNotNull(superTypesArray[j]);
if (superTypes.contains(superType)) {
continue;
}

superTypes.add(superType);
getSuperTypes(superType, superTypes);
}
}

private PsiClassType chooseTypeByUser(List allowedTypes, PsiVariable variable, Project project) throws AbortException {
final PsiClassType currentType = getClassTypeNotNull(variable.getType());
allowedTypes.remove(currentType);
final PsiClassType typeToSelect = (PsiClassType)allowedTypes.get(0);

final TypeChooserDialog dialog = new TypeChooserDialog(project);
dialog.setTypes(allowedTypes, typeToSelect, currentType.getCanonicalText(), variable.getName());
dialog.show();
if (!dialog.isOK()) {
return null;
}

return dialog.getSelectedType();
}

private void replaceVariableType(PsiClassType newType, PsiVariable variable, PsiElementFactory elementFactory) {
final PsiTypeElement typeElementForReplacing = elementFactory.createTypeElement(newType);
try {
variable.normalizeDeclaration();
variable.getTypeElement().replace(typeElementForReplacing);
}
catch (IncorrectOperationException ex) {
LOG.error("", ex);
}
}
}

0

Hi Sascha,

Thanks, this is a very nice idea! I now try to enhance it, that when
multiple references of the variable are within this method call, all of them
get replaced with "(FQN)null".

Tom

0

How to create a PsiClass by type name with generics (for example, "List<String>")?

P.S. The code below returns null

     PsiManager.getInstance(project).findClass("List<String>", scope)

0

Hello Alexei,

There is no way to create such a PsiClass. What do you need to accomplish?

How to create a PsiClass by type name with generics (for example,
"List<String>")?

P.S. The code below returns null

PsiManager.getInstance(project).findClass("List<String>", scope)

---
Original message URL:
http://www.jetbrains.net/devnet/message/5239985#5239985

--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"


0

Please sign in to leave a comment.