IDEA-91164 Should have an Intention to strongly type groovy variable

This commit is contained in:
Max Medvedev
2012-09-10 11:47:36 +04:00
parent 7be2ecad0b
commit b790132830
8 changed files with 136 additions and 11 deletions
@@ -0,0 +1 @@
<spot>int</spot> abc = 5
@@ -0,0 +1 @@
<spot>def</spot> abc = 5
@@ -0,0 +1,5 @@
<html>
<body>
This intention inserts type declaration to the selected variable.
</body>
</html>
+5
View File
@@ -1215,6 +1215,11 @@
<categoryKey>intention.category.groovy/intention.category.groovy.declaration</categoryKey>
<className>org.jetbrains.plugins.groovy.intentions.declaration.GrCreateFieldForParameterIntention</className>
</intentionAction>
<intentionAction>
<bundleName>org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle</bundleName>
<categoryKey>intention.category.groovy/intention.category.groovy.declaration</categoryKey>
<className>org.jetbrains.plugins.groovy.intentions.declaration.GrSetStrongTypeIntention</className>
</intentionAction>
<!--other-->
<intentionAction>
@@ -166,6 +166,8 @@ gr.convert.string.to.char.intention.name=Cast to char
gr.convert.string.to.char.intention.family.name=Cast to char
create.field.for.parameter.0 = Create Field for Parameter {0}
create.field.for.parameter=Create Field for Parameter
gr.set.strong.type.intention.name=Declare explicit type
gr.set.strong.type.intention.family.name=Declare explicit type
remove.unnecessary.escape.characters.intention.name=Remove unnecessary escape characters
remove.unnecessary.escape.characters.intention.family.name=Remove unnecessary escape characters
gr.break.string.on.line.breaks.intention.name=Break string on '\\n'
@@ -0,0 +1,114 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.intentions.declaration;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiType;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.intentions.base.Intention;
import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.template.expressions.ChooseTypeExpression;
import java.util.ArrayList;
/**
* Created with IntelliJ IDEA.
* User: maxmedvedev
* Date: 9/8/12
* Time: 9:55
* To change this template use File | Settings | File Templates.
*/
public class GrSetStrongTypeIntention extends Intention {
@Override
protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException {
if (element instanceof GrVariableDeclaration) {
GrVariable[] variables = ((GrVariableDeclaration)element).getVariables();
ArrayList<TypeConstraint> types = new ArrayList<TypeConstraint>();
for (GrVariable variable : variables) {
if (variable.getInitializerGroovy() != null) {
PsiType type = variable.getInitializerGroovy().getType();
types.add(SupertypeConstraint.create(type));
}
}
TemplateBuilderImpl builder = new TemplateBuilderImpl(element);
PsiManager manager = element.getManager();
GrModifierList modifierList = ((GrVariableDeclaration)element).getModifierList();
if (modifierList.hasModifierProperty(GrModifier.DEF) && modifierList.getModifiers().length == 1) {
PsiElement def = PsiUtil.findModifierInList(modifierList, GrModifier.DEF);
builder.replaceElement(def, new ChooseTypeExpression(types.toArray(new TypeConstraint[types.size()]), manager));
}
else {
((GrVariableDeclaration)element).setType(TypesUtil.createType("Abc", element));
GrTypeElement typeElement = ((GrVariableDeclaration)element).getTypeElementGroovy();
builder.replaceElement(typeElement, new ChooseTypeExpression(types.toArray(new TypeConstraint[types.size()]), manager));
}
final PsiElement afterPostprocess = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(element);
final Template template = builder.buildTemplate();
TextRange range = afterPostprocess.getTextRange();
Document document = editor.getDocument();
document.deleteString(range.getStartOffset(), range.getEndOffset());
TemplateManager templateManager = TemplateManager.getInstance(project);
templateManager.startTemplate(editor, template);
}
}
@NotNull
@Override
protected PsiElementPredicate getElementPredicate() {
return new PsiElementPredicate() {
@Override
public boolean satisfiedBy(PsiElement element) {
if (element instanceof GrVariableDeclaration && ((GrVariableDeclaration)element).getTypeElementGroovy() == null) {
GrVariable[] variables = ((GrVariableDeclaration)element).getVariables();
for (GrVariable variable : variables) {
if (variable.getInitializerGroovy() != null) return true;
}
}
return false;
}
};
}
}
@@ -1008,15 +1008,9 @@ public class ExpressionGenerator extends Generator {
@Override
public void visitThisSuperReferenceExpression(GrThisSuperReferenceExpression expr) {
if (context.isInAnonymousContext() && expr.getQualifier() == null) {
builder.append(expr.getReferenceName());
return;
}
final PsiElement resolved = expr.resolve();
LOG.assertTrue(resolved instanceof PsiClass);
if (!(resolved instanceof PsiAnonymousClass)) {
builder.append(((PsiClass)resolved).getQualifiedName()).append('.');
GrReferenceExpression qualifier = expr.getQualifier();
if (!context.isInAnonymousContext() && qualifier != null) {
qualifier.accept(this);
}
builder.append(expr.getReferenceName());
}
@@ -27,6 +27,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SubtypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -88,8 +89,7 @@ public class ChooseTypeExpression extends Expression {
private PsiType chooseType(TypeConstraint[] constraints) {
if (constraints.length > 0) return constraints[0].getDefaultType();
return JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory()
.createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, GlobalSearchScope.allScope(myManager.getProject()));
return PsiType.getJavaLangObject(myManager, GlobalSearchScope.allScope(myManager.getProject()));
}
public Result calculateResult(ExpressionContext context) {
@@ -100,6 +100,9 @@ public class ChooseTypeExpression extends Expression {
return new TextResult(GrModifier.DEF);
}
type = TypesUtil.unboxPrimitiveTypeWrapper(type);
if (type == null) return null;
return new PsiTypeResult(type, context.getProject()) {
@Override
public void handleRecalc(PsiFile psiFile, Document document, int segmentStart, int segmentEnd) {