QuickFix: adding <*> for 'raw' type inside javaClass() call

This commit is contained in:
Andrey Breslav
2012-12-05 21:00:56 +04:00
parent f0ce7ac33a
commit 2948875cad
10 changed files with 107 additions and 7 deletions
@@ -19,19 +19,19 @@ package org.jetbrains.jet.plugin.quickfix;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetTypeElement;
import org.jetbrains.jet.lang.psi.JetUserType;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.plugin.JetBundle;
public class AddStarProjectionsFix extends JetIntentionAction<JetUserType> {
public abstract class AddStarProjectionsFix extends JetIntentionAction<JetUserType> {
private final int argumentCount;
@@ -68,7 +68,7 @@ public class AddStarProjectionsFix extends JetIntentionAction<JetUserType> {
return true;
}
public static JetIntentionActionFactory createFactory() {
public static JetIntentionActionFactory createFactoryForIsExpression() {
return new JetIntentionActionFactory() {
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
@@ -79,7 +79,50 @@ public class AddStarProjectionsFix extends JetIntentionAction<JetUserType> {
JetUserType userType = QuickFixUtil.getParentElementOfType(diagnostic, JetUserType.class);
if (userType == null) return null;
Integer size = diagnosticWithParameters.getA();
return new AddStarProjectionsFix(userType, size);
return new AddStarProjectionsFix(userType, size) {};
}
};
}
public static JetIntentionActionFactory createFactoryForJavaClass() {
return new JetIntentionActionFactory() {
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
assert diagnostic.getFactory() == Errors.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
@SuppressWarnings("unchecked")
DiagnosticWithParameters1<JetElement, Integer> diagnosticWithParameters = (DiagnosticWithParameters1) diagnostic;
Integer size = diagnosticWithParameters.getA();
JetUserType userType = QuickFixUtil.getParentElementOfType(diagnostic, JetUserType.class);
if (userType == null) return null;
return new AddStarProjectionsFix(userType, size) {
@Override
public boolean isAvailable(
@NotNull Project project, Editor editor, PsiFile file
) {
// We are looking for the occurrence of Type in javaClass<Type>()
return super.isAvailable(project, editor, file) && isZeroTypeArguments() && isInsideJavaClassCall();
}
private boolean isZeroTypeArguments() {
return element.getTypeArguments().isEmpty();
}
private boolean isInsideJavaClassCall() {
PsiElement parent = element.getParent().getParent().getParent().getParent();
if (parent instanceof JetCallExpression) {
JetExpression calleeExpression = ((JetCallExpression) parent).getCalleeExpression();
if (calleeExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) calleeExpression;
// Resolve is expensive so we use a heuristic here: the case is rare enough not to be annoying
return "javaClass".equals(simpleNameExpression.getReferencedName());
}
}
return false;
}
};
}
};
}
@@ -145,6 +145,7 @@ public class QuickFixes {
factories.put(NO_ELSE_IN_WHEN, AddWhenElseBranchFix.createFactory());
factories.put(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION, AddStarProjectionsFix.createFactory());
factories.put(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION, AddStarProjectionsFix.createFactoryForIsExpression());
factories.put(WRONG_NUMBER_OF_TYPE_ARGUMENTS, AddStarProjectionsFix.createFactoryForJavaClass());
}
}
@@ -0,0 +1,9 @@
// "Add '<*, *>'" "false"
// ERROR: Type argument expected
class C2<T>
fun foo<T>() {}
fun test() {
foo<C2<caret>>()
}
@@ -0,0 +1,6 @@
// "Add '<*>'" "true"
class C1<T>
fun test() {
javaClass<C1<*>>()
}
@@ -0,0 +1,6 @@
// "Add '<*, *>'" "true"
class C2<T, R>
fun test() {
javaClass<C2<*, *>>()
}
@@ -0,0 +1,7 @@
// "Add '<*>'" "false"
// "Add '<*, *>'" "false"
class C
fun test() {
javaClass<C<caret>>
}
@@ -0,0 +1,9 @@
// "Add '<*, *>'" "false"
// ERROR: Type argument expected
class C2<T>
fun foo<T>() {}
fun test() {
foo<C2<caret>>()
}
@@ -0,0 +1,6 @@
// "Add '<*>'" "true"
class C1<T>
fun test() {
javaClass<C1<caret>>()
}
@@ -0,0 +1,6 @@
// "Add '<*, *>'" "true"
class C2<T, R>
fun test() {
javaClass<C2<caret>>()
}
@@ -0,0 +1,7 @@
// "Add '<*>'" "false"
// "Add '<*, *>'" "false"
class C
fun test() {
javaClass<C<caret>>()
}