IDEA-99867 Groovy Static type checking: parameters of closures should have explict types. Intention to insert type

This commit is contained in:
Max Medvedev
2013-03-29 17:09:31 +04:00
parent 23a72776b6
commit c8e11c61eb
2 changed files with 43 additions and 14 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -23,10 +23,7 @@ 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.PsiClassType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -36,12 +33,16 @@ 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.statements.clauses.GrForInClause;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList;
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.typeEnhancers.ClosureParameterEnhancer;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.template.expressions.ChooseTypeExpression;
@@ -70,6 +71,10 @@ public class GrSetStrongTypeIntention extends Intention {
variables = ((GrVariableDeclaration)parent).getVariables();
elementToBuildTemplate = parent;
}
else if (parent instanceof GrParameter && parent.getParent() instanceof GrParameterList) {
variables = new GrVariable[]{(GrVariable)parent};
elementToBuildTemplate = parent.getParent().getParent();
}
else if (parent instanceof GrVariable) {
variables = new GrVariable[]{((GrVariable)parent)};
elementToBuildTemplate = parent;
@@ -92,6 +97,13 @@ public class GrSetStrongTypeIntention extends Intention {
types.add(SupertypeConstraint.create(type));
}
}
if (variable instanceof GrParameter) {
final PsiParameter parameter = (PsiParameter)variable;
final PsiType type = getClosureParameterType(parameter);
if (type != null) {
types.add(SupertypeConstraint.create(type));
}
}
}
}
@@ -116,6 +128,19 @@ public class GrSetStrongTypeIntention extends Intention {
templateManager.startTemplate(editor, template);
}
@Nullable
private static PsiType getClosureParameterType(@NotNull PsiParameter parameter) {
final PsiElement scope = parameter.getDeclarationScope();
final PsiType type;
if (scope instanceof GrClosableBlock) {
type = ClosureParameterEnhancer.inferType((GrClosableBlock)scope, ((GrParameterList)parameter.getParent()).getParameterIndex(parameter));
}
else {
type = null;
}
return type;
}
@Nullable
private static PsiElement setType(PsiElement element, PsiElement parent, PsiElement elementToBuildTemplate) {
GrModifierList modifierList = getModifierList(parent);
@@ -187,6 +212,9 @@ public class GrSetStrongTypeIntention extends Intention {
else if (pparent instanceof GrForInClause) {
return PsiUtil.extractIteratedType((GrForInClause)pparent) != null;
}
else if (parent instanceof GrParameter && pparent instanceof GrParameterList) {
return getClosureParameterType((PsiParameter)parent) != null;
}
else {
return isVarDeclaredWithInitializer((GrVariable)parent);
}
@@ -19,7 +19,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.containers.hash.HashSet;
@@ -34,7 +33,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrStringInjection;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrRangeType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil;
@@ -49,10 +47,10 @@ import static com.intellij.psi.CommonClassNames.JAVA_IO_FILE;
* @author peter
*/
public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer {
private final Map<String, String> simpleTypes = new HashMap<String, String>();
private final Set<String> iterations = new HashSet<String>();
private static final Map<String, String> simpleTypes = new HashMap<String, String>();
private static final Set<String> iterations = new HashSet<String>();
public ClosureParameterEnhancer() {
static {
simpleTypes.put("times", "java.lang.Integer");
simpleTypes.put("upto", "java.lang.Integer");
simpleTypes.put("downto", "java.lang.Integer");
@@ -105,22 +103,25 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer {
iterations.add("findIndexValues");
iterations.add("findIndexOf");
iterations.add("count");
}
@Override
@Nullable
protected PsiType getClosureParameterType(GrClosableBlock closure, int index) {
final PsiMember containingMember = PsiTreeUtil.getParentOfType(closure, PsiMember.class);
if (containingMember != null && GroovyPsiManager.getInstance(closure.getProject()).isCompileStatic(containingMember)) {
if (org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isCompileStatic(closure)) {
return null;
}
return inferType(closure, index);
}
@Nullable
public static PsiType inferType(@NotNull GrClosableBlock closure, int index) {
PsiElement parent = closure.getParent();
if (parent instanceof GrStringInjection && index == 0) {
return TypesUtil.createTypeByFQClassName("java.io.StringWriter", closure);
}
if (parent instanceof GrArgumentList) parent = parent.getParent();
if (!(parent instanceof GrMethodCall)) {
return null;