quickfix to move type constraint to 'where' clause

This commit is contained in:
Dmitry Jemerov
2015-10-06 19:03:42 +02:00
parent 4c4030dfc1
commit 45d1129dbb
15 changed files with 114 additions and 10 deletions
@@ -268,7 +268,7 @@ public interface Errors {
DiagnosticFactory0<PsiElement> CYCLIC_GENERIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetTypeParameter> MISPLACED_TYPE_PARAMETER_CONSTRAITS = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<JetTypeParameter> MISPLACED_TYPE_PARAMETER_CONSTRAINTS = DiagnosticFactory0.create(WARNING);
// Members
@@ -496,7 +496,7 @@ public class DefaultErrorMessages {
MAP.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Placing function type parameters after the function name is deprecated");
MAP.put(MISPLACED_TYPE_PARAMETER_CONSTRAITS, "If a type parameter has multiple constraints, they all need to be placed in the 'where' clause");
MAP.put(MISPLACED_TYPE_PARAMETER_CONSTRAINTS, "If a type parameter has multiple constraints, they all need to be placed in the 'where' clause");
MAP.put(TYPE_VARIANCE_CONFLICT, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in type {3}",
new MultiRenderer<VarianceConflictDiagnosticData>() {
@@ -342,7 +342,7 @@ public class DeclarationsChecker {
if (!constraints.isEmpty()) {
for (JetTypeParameter typeParameter : typeParameterListOwner.getTypeParameters()) {
if (typeParameter.getExtendsBound() != null && hasConstraints(typeParameter, constraints)) {
trace.report(MISPLACED_TYPE_PARAMETER_CONSTRAITS.on(typeParameter));
trace.report(MISPLACED_TYPE_PARAMETER_CONSTRAINTS.on(typeParameter));
}
}
}
@@ -1,9 +1,9 @@
class Foo<<!MISPLACED_TYPE_PARAMETER_CONSTRAITS!>T : Cloneable<!>> where T : Comparable<T> {
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAITS!>U : Cloneable<!>> foo(u: U): U where U: Comparable<U> {
class Foo<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T : Cloneable<!>> where T : Comparable<T> {
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>U : Cloneable<!>> foo(u: U): U where U: Comparable<U> {
return u
}
val <<!MISPLACED_TYPE_PARAMETER_CONSTRAITS!>U : Cloneable<!>> U.foo: U? where U: Comparable<U>
val <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>U : Cloneable<!>> U.foo: U? where U: Comparable<U>
get() { return null }
}
@@ -93,7 +93,8 @@ public class KotlinCleanupInspection(): LocalInspectionTool(), CleanupLocalInspe
Errors.BACKING_FIELD_SYNTAX_DEPRECATED,
Errors.OPERATOR_MODIFIER_REQUIRED,
Errors.CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS,
Errors.DEPRECATED_TYPE_PARAMETER_SYNTAX
Errors.DEPRECATED_TYPE_PARAMETER_SYNTAX,
Errors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS
)
private fun Diagnostic.isObsoleteLabel(): Boolean {
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2015 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.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class MoveTypeParameterConstraintFix(element: JetTypeParameter) : JetIntentionAction<JetTypeParameter>(element), CleanupFix {
override fun getText(): String = "Move type parameter constraint to 'where' clause"
override fun getFamilyName(): String = text
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
val typeParameterName = element.nameAsName ?: return
val psiFactory = JetPsiFactory(file)
val templateClass = psiFactory.buildDeclaration {
appendFixedText("class A<")
appendName(typeParameterName)
appendFixedText("> where ")
appendName(typeParameterName)
appendFixedText(":")
appendTypeReference(element.extendsBound)
} as JetTypeParameterListOwner
val templateConstraintList = templateClass.typeConstraintList!!
val declaration = element.getStrictParentOfType<JetTypeParameterListOwner>() ?: return
val constraintList = declaration.typeConstraintList ?: return
constraintList.addAfter(psiFactory.createComma(), null)
constraintList.addAfter(templateConstraintList.constraints[0], null)
element.extendsBound?.delete()
val colon = element.node.findChildByType(JetTokens.COLON)
colon?.psi?.delete()
}
companion object : JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val typeParameter = diagnostic.psiElement as? JetTypeParameter ?: return null
return MoveTypeParameterConstraintFix(typeParameter)
}
}
}
@@ -340,5 +340,7 @@ public class QuickFixRegistrar : QuickFixContributor {
DEPRECATED_TYPE_PARAMETER_SYNTAX.registerFactory(MigrateTypeParameterListFix)
UNRESOLVED_REFERENCE.registerFactory(KotlinAddOrderEntryActionFactory)
MISPLACED_TYPE_PARAMETER_CONSTRAINTS.registerFactory(MoveTypeParameterConstraintFix)
}
}
+5 -3
View File
@@ -14,8 +14,9 @@ class D() {
companion object : A(), B {}
}
class Test1<T : A>()
class Test1<T>()
where
T : A,
T : B,
<error>B</error> : T // error
{
@@ -41,10 +42,11 @@ class Bar<T : <warning>Foo</warning>>
class Buzz<T> where T : <warning>Bar<<error>Int</error>></warning>, T : <error>nioho</error>
class X<T : <warning>Foo</warning>>
class Y<<error>T</error> : <warning>Foo</warning>> where T : <warning>Bar<Foo></warning>
class Y<<error>T</error>> where T : <warning>Foo</warning>, T : <warning>Bar<Foo></warning>
fun <T : A> test2(t : T)
fun <T> test2(t : T)
where
T : A,
T : B,
<error>B</error> : T
{
+3
View File
@@ -63,3 +63,6 @@ class C {
fun typed<T>() {
}
fun <T : Cloneable> withTypeParameters() where T : Comparable<T> {
}
+3
View File
@@ -62,3 +62,6 @@ class C {
fun <T> typed() {
}
fun <T> withTypeParameters() where T : Cloneable, T : Comparable<T> {
}
@@ -0,0 +1,3 @@
// "Move type parameter constraint to 'where' clause" "true"
class A<<caret>T : Cloneable> where T : Comparable<*> {
}
@@ -0,0 +1,3 @@
// "Move type parameter constraint to 'where' clause" "true"
class A<T> where T : Cloneable, T : Comparable<*> {
}
@@ -0,0 +1,3 @@
// "Move type parameter constraint to 'where' clause" "true"
fun <<caret>T : Cloneable> foo() where T : Comparable<*> {
}
@@ -0,0 +1,3 @@
// "Move type parameter constraint to 'where' clause" "true"
fun <T> foo() where T : Cloneable, T : Comparable<*> {
}
@@ -6544,6 +6544,27 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
}
}
@TestMetadata("idea/testData/quickfix/typeParameters")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeParameters extends AbstractQuickFixTest {
public void testAllFilesPresentInTypeParameters() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/typeParameters"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("misplacedClassTypeParameter.kt")
public void testMisplacedClassTypeParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeParameters/misplacedClassTypeParameter.kt");
doTest(fileName);
}
@TestMetadata("misplacedFunctionTypeParameter.kt")
public void testMisplacedFunctionTypeParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeParameters/misplacedFunctionTypeParameter.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/quickfix/typeProjection")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)