create Java field from usage in Groovy code

This commit is contained in:
Maxim.Medvedev
2012-06-21 15:14:10 +04:00
parent 36b248a552
commit e6b66d6703
8 changed files with 65 additions and 57 deletions
@@ -25,7 +25,6 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
@@ -81,22 +80,8 @@ public class CreateFieldFromUsageFix extends CreateVarFromUsageFix {
PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true);
}
if (enclosingContext != null &&
enclosingContext.getParent() == parentClass &&
targetClass == parentClass &&
enclosingContext instanceof PsiField) {
field = (PsiField)targetClass.addBefore(field, enclosingContext);
}
else if (enclosingContext != null &&
enclosingContext.getParent() == parentClass &&
targetClass == parentClass &&
enclosingContext instanceof PsiClassInitializer) {
field = (PsiField)targetClass.addBefore(field, enclosingContext);
targetClass.addBefore(CodeEditUtil.createLineFeed(field.getManager()), enclosingContext);
}
else {
field = (PsiField)targetClass.add(field);
}
field = CreateFieldFromUsageHelper.insertField(targetClass, field, myReferenceExpression);
setupVisibility(parentClass, targetClass, field.getModifierList());
@@ -41,6 +41,14 @@ public abstract class CreateFieldFromUsageHelper {
CreateFromUsageBaseFix.getTargetSubstitutor(context));
}
public static PsiField insertField(PsiClass targetClass, PsiField field, PsiElement place) {
CreateFieldFromUsageHelper helper = EP_NAME.forLanguage(field.getLanguage());
if (helper == null) return null;
return helper.insertFieldImpl(targetClass, field, place);
}
public abstract PsiField insertFieldImpl(PsiClass targetClass, PsiField field, PsiElement place);
public abstract Template setupTemplateImpl(PsiField field,
Object expectedTypes,
PsiClass targetClass,
@@ -22,6 +22,8 @@ import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.util.PsiTreeUtil;
/**
* @author Max Medvedev
@@ -60,4 +62,34 @@ public class JavaCreateFieldFromUsageHelper extends CreateFieldFromUsageHelper {
if (((ExpectedTypeInfo[])expectedTypes).length > 1) template.setToShortenLongNames(false);
return template;
}
public PsiField insertFieldImpl(PsiClass targetClass, PsiField field, PsiElement place) {
PsiMember enclosingContext = null;
PsiClass parentClass;
do {
enclosingContext = PsiTreeUtil.getParentOfType(enclosingContext == null ? place : enclosingContext, PsiMethod.class, PsiField.class, PsiClassInitializer.class);
parentClass = enclosingContext == null ? null : enclosingContext.getContainingClass();
}
while (parentClass instanceof PsiAnonymousClass);
if (enclosingContext != null &&
enclosingContext.getParent() == parentClass &&
targetClass == parentClass &&
enclosingContext instanceof PsiField) {
field = (PsiField)targetClass.addBefore(field, enclosingContext);
}
else if (enclosingContext != null &&
enclosingContext.getParent() == parentClass &&
targetClass == parentClass &&
enclosingContext instanceof PsiClassInitializer) {
field = (PsiField)targetClass.addBefore(field, enclosingContext);
targetClass.addBefore(CodeEditUtil.createLineFeed(field.getManager()), enclosingContext);
}
else {
field = (PsiField)targetClass.add(field);
}
return field;
}
}
@@ -1778,9 +1778,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
}
if (targetClass.isWritable()) {
if (!(targetClass instanceof GroovyScriptClass)) {
if (targetClass instanceof GrMemberOwner) {
annotation.registerFix(new CreateFieldFromUsageFix(refExpr, (GrMemberOwner)targetClass));
}
annotation.registerFix(new CreateFieldFromUsageFix(refExpr, targetClass));
}
if (refExpr.getParent() instanceof GrCall && refExpr.getParent() instanceof GrExpression) {
@@ -15,36 +15,27 @@
*/
package org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFieldFromUsageHelper;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.plugins.groovy.lang.editor.template.expressions.ChooseTypeExpression;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
/**
* @author Maxim.Medvedev
*/
public class CreateFieldFix {
private final GrMemberOwner myTargetClass;
private final PsiClass myTargetClass;
protected GrMemberOwner getTargetClass() {
protected PsiClass getTargetClass() {
return myTargetClass;
}
protected CreateFieldFix(GrMemberOwner targetClass) {
protected CreateFieldFix(PsiClass targetClass) {
myTargetClass = targetClass;
}
@@ -52,28 +43,17 @@ public class CreateFieldFix {
return myTargetClass.isValid();
}
protected void doFix(Project project, String[] modifiers, String fieldName, TypeConstraint[] typeConstraints) throws IncorrectOperationException {
PsiClassType type = JavaPsiFacade.getElementFactory(project).createTypeByFQClassName("Object", GlobalSearchScope.allScope(project));
GrVariableDeclaration fieldDecl =
GroovyPsiElementFactory.getInstance(project).createFieldDeclaration(modifiers, fieldName, null, type);
fieldDecl = (GrVariableDeclaration)myTargetClass.add(fieldDecl);
GrTypeElement typeElement = fieldDecl.getTypeElementGroovy();
assert typeElement != null;
ChooseTypeExpression expr = new ChooseTypeExpression(typeConstraints, PsiManager.getInstance(project));
TemplateBuilderImpl builder = new TemplateBuilderImpl(fieldDecl);
builder.replaceElement(typeElement, expr);
fieldDecl = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(fieldDecl);
if (fieldDecl == null) {
return;
protected void doFix(Project project, String[] modifiers, String fieldName, TypeConstraint[] typeConstraints, PsiElement context) throws IncorrectOperationException {
PsiField field = JVMElementFactories.getFactory(myTargetClass.getLanguage(), project).createField(fieldName, PsiType.INT);
for (String modifier : modifiers) {
PsiUtil.setModifierProperty(field, modifier, true);
}
Template template = builder.buildTemplate();
field = CreateFieldFromUsageHelper.insertField(myTargetClass, field, context);
Editor newEditor = QuickfixUtil.positionCursor(project, myTargetClass.getContainingFile(), fieldDecl);
TextRange range = fieldDecl.getTextRange();
newEditor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset());
Editor newEditor = QuickfixUtil.positionCursor(project, myTargetClass.getContainingFile(), field);
Template template = CreateFieldFromUsageHelper.setupTemplate(field, typeConstraints, myTargetClass, newEditor, context, false);
TemplateManager manager = TemplateManager.getInstance(project);
manager.startTemplate(newEditor, template);
}
@@ -72,6 +72,6 @@ public class CreateFieldFromConstructorLabelFix extends GroovyFix {
@Override
protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
myFix.doFix(project, ArrayUtil.EMPTY_STRING_ARRAY, getFieldName(), calculateTypeConstrains());
myFix.doFix(project, ArrayUtil.EMPTY_STRING_ARRAY, getFieldName(), calculateTypeConstrains(), myNamedArgument);
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiModifier;
import com.intellij.util.ArrayUtil;
@@ -26,7 +27,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
@@ -38,7 +38,7 @@ public class CreateFieldFromUsageFix implements IntentionAction {
private final CreateFieldFix myFix;
private final GrReferenceExpression myRefExpression;
public CreateFieldFromUsageFix(GrReferenceExpression refExpression, GrMemberOwner targetClass) {
public CreateFieldFromUsageFix(GrReferenceExpression refExpression, PsiClass targetClass) {
myFix = new CreateFieldFix(targetClass);
myRefExpression = refExpression;
}
@@ -75,7 +75,7 @@ public class CreateFieldFromUsageFix implements IntentionAction {
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
myFix.doFix(project, generateModifiers(), getFieldName(), calculateTypeConstrains());
myFix.doFix(project, generateModifiers(), getFieldName(), calculateTypeConstrains(), myRefExpression);
}
@Override
@@ -80,4 +80,9 @@ public class GroovyCreateFieldFromUsageHelper extends CreateFieldFromUsageHelper
}
return template;
}
@Override
public PsiField insertFieldImpl(PsiClass targetClass, PsiField field, PsiElement place) {
return (PsiField)targetClass.add(field);
}
}