Added second quickfix on conflicting extension to mark it hidden and deprecated

This commit is contained in:
Valentin Kipyatkov
2015-08-31 23:43:02 +03:00
parent b2ea369129
commit 086d29a44a
36 changed files with 91 additions and 31 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.inspections package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInspection.* import com.intellij.codeInspection.*
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@@ -44,6 +45,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedAsHidden import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedAsHidden
import org.jetbrains.kotlin.resolve.scopes.FileScope import org.jetbrains.kotlin.resolve.scopes.FileScope
@@ -67,12 +69,25 @@ public class ConflictingExtensionPropertyInspection : AbstractKotlinInspection()
// don't report on hidden declarations // don't report on hidden declarations
if (propertyDescriptor.isAnnotatedAsHidden()) return if (propertyDescriptor.isAnnotatedAsHidden()) return
val fixes = if (isSameAsSynthetic(property, conflictingExtension)) {
val fix1 = IntentionWrapper(DeleteRedundantExtensionAction(property), file)
// don't add the second fix when on the fly to allow code cleanup
val fix2 = if (isOnTheFly)
object : IntentionWrapper(MarkHiddenAndDeprecatedAction(property), file), LowPriorityAction {}
else
null
listOf(fix1, fix2).filterNotNull().toTypedArray()
}
else {
emptyArray()
}
val problemDescriptor = holder.manager.createProblemDescriptor( val problemDescriptor = holder.manager.createProblemDescriptor(
nameElement, nameElement,
"This property conflicts with synthetic extension and should be removed to avoid breaking code by future changes in the compiler", "This property conflicts with synthetic extension and should be removed to avoid breaking code by future changes in the compiler",
createQuickFix(property, conflictingExtension), true,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fixes,
true ProblemHighlightType.GENERIC_ERROR_OR_WARNING
) )
holder.registerProblem(problemDescriptor) holder.registerProblem(problemDescriptor)
} }
@@ -88,18 +103,18 @@ public class ConflictingExtensionPropertyInspection : AbstractKotlinInspection()
.firstIsInstanceOrNull() .firstIsInstanceOrNull()
} }
private fun createQuickFix(declaration: JetProperty, syntheticProperty: SyntheticJavaPropertyDescriptor): LocalQuickFix? { private fun isSameAsSynthetic(declaration: JetProperty, syntheticProperty: SyntheticJavaPropertyDescriptor): Boolean {
val getter = declaration.getter ?: return null val getter = declaration.getter ?: return false
val setter = declaration.setter val setter = declaration.setter
if (!checkGetterBodyIsGetMethodCall(getter, syntheticProperty.getMethod)) return null if (!checkGetterBodyIsGetMethodCall(getter, syntheticProperty.getMethod)) return false
if (setter != null) { if (setter != null) {
val setMethod = syntheticProperty.setMethod ?: return null // synthetic property is val but our property is var val setMethod = syntheticProperty.setMethod ?: return false // synthetic property is val but our property is var
if (!checkSetterBodyIsSetMethodCall(setter, setMethod)) return null if (!checkSetterBodyIsSetMethodCall(setter, setMethod)) return false
} }
return IntentionWrapper(DeleteRedundantExtensionAction(declaration), declaration.containingFile) return true
} }
private fun checkGetterBodyIsGetMethodCall(getter: JetPropertyAccessor, getMethod: FunctionDescriptor): Boolean { private fun checkGetterBodyIsGetMethodCall(getter: JetPropertyAccessor, getMethod: FunctionDescriptor): Boolean {
@@ -196,4 +211,31 @@ public class ConflictingExtensionPropertyInspection : AbstractKotlinInspection()
} }
} }
} }
private class MarkHiddenAndDeprecatedAction(property: JetProperty) : JetIntentionAction<JetProperty>(property) {
override fun getFamilyName() = "Mark with @HiddenDeclaration and @deprecated"
override fun getText() = familyName
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
val factory = JetPsiFactory(project)
val name = element.nameAsName!!.render()
element.addAnnotationWithLineBreak(factory.createAnnotationEntry("@deprecated(\"Is replaced with automatic synthetic extension\", ReplaceWith(\"$name\"))"))
element.addAnnotationWithLineBreak(factory.createAnnotationEntry("@HiddenDeclaration"))
}
//TODO: move into PSI?
private fun JetNamedDeclaration.addAnnotationWithLineBreak(annotationEntry: JetAnnotationEntry): JetAnnotationEntry {
val newLine = JetPsiFactory(this).createNewLine()
if (modifierList != null) {
val result = addAnnotationEntry(annotationEntry)
modifierList!!.addAfter(newLine, result)
return result
}
else {
val result = addAnnotationEntry(annotationEntry)
addAfter(newLine, modifierList)
return result
}
}
}
} }
@@ -0,0 +1,5 @@
// "Mark with @HiddenDeclaration and @deprecated" "true"
import java.io.File
val File.<caret>name: String
get() = getName()
@@ -0,0 +1,7 @@
// "Mark with @HiddenDeclaration and @deprecated" "true"
import java.io.File
@HiddenDeclaration
@deprecated("Is replaced with automatic synthetic extension", ReplaceWith("name"))
val File.<caret>name: String
get() = getName()
@@ -990,23 +990,23 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
} }
@TestMetadata("idea/testData/quickfix/migration/deleteRedundantExtension") @TestMetadata("idea/testData/quickfix/migration/conflictingExtension")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
public static class DeleteRedundantExtension extends AbstractQuickFixMultiFileTest { public static class ConflictingExtension extends AbstractQuickFixMultiFileTest {
public void testAllFilesPresentInDeleteRedundantExtension() throws Exception { public void testAllFilesPresentInConflictingExtension() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/deleteRedundantExtension"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/conflictingExtension"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
} }
@TestMetadata("removeImports.before.Main.kt") @TestMetadata("removeImports.before.Main.kt")
public void testRemoveImports() throws Exception { public void testRemoveImports() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/removeImports.before.Main.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/removeImports.before.Main.kt");
doTestWithExtraFile(fileName); doTestWithExtraFile(fileName);
} }
@TestMetadata("removeImportsOverloads.before.Main.kt") @TestMetadata("removeImportsOverloads.before.Main.kt")
public void testRemoveImportsOverloads() throws Exception { public void testRemoveImportsOverloads() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/removeImportsOverloads.before.Main.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/removeImportsOverloads.before.Main.kt");
doTestWithExtraFile(fileName); doTestWithExtraFile(fileName);
} }
} }
@@ -3923,83 +3923,89 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
} }
@TestMetadata("idea/testData/quickfix/migration/deleteRedundantExtension") @TestMetadata("idea/testData/quickfix/migration/conflictingExtension")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
public static class DeleteRedundantExtension extends AbstractQuickFixTest { public static class ConflictingExtension extends AbstractQuickFixTest {
public void testAllFilesPresentInDeleteRedundantExtension() throws Exception { public void testAllFilesPresentInConflictingExtension() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/deleteRedundantExtension"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/conflictingExtension"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
} }
@TestMetadata("explicitThis.kt") @TestMetadata("explicitThis.kt")
public void testExplicitThis() throws Exception { public void testExplicitThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/explicitThis.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/explicitThis.kt");
doTest(fileName);
}
@TestMetadata("markHiddenAndDeprecated.kt")
public void testMarkHiddenAndDeprecated() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/markHiddenAndDeprecated.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("memberExtension.kt") @TestMetadata("memberExtension.kt")
public void testMemberExtension() throws Exception { public void testMemberExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/memberExtension.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/memberExtension.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("returnInGetter.kt") @TestMetadata("returnInGetter.kt")
public void testReturnInGetter() throws Exception { public void testReturnInGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/returnInGetter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/returnInGetter.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("simple.kt") @TestMetadata("simple.kt")
public void testSimple() throws Exception { public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/simple.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/simple.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("valInsteadOfVar.kt") @TestMetadata("valInsteadOfVar.kt")
public void testValInsteadOfVar() throws Exception { public void testValInsteadOfVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/valInsteadOfVar.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/valInsteadOfVar.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("varInsteadOfVal.kt") @TestMetadata("varInsteadOfVal.kt")
public void testVarInsteadOfVal() throws Exception { public void testVarInsteadOfVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/varInsteadOfVal.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/varInsteadOfVal.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("withSetter.kt") @TestMetadata("withSetter.kt")
public void testWithSetter() throws Exception { public void testWithSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/withSetter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/withSetter.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("wrongExplicitThis.kt") @TestMetadata("wrongExplicitThis.kt")
public void testWrongExplicitThis() throws Exception { public void testWrongExplicitThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongExplicitThis.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/wrongExplicitThis.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("wrongExplicitThis2.kt") @TestMetadata("wrongExplicitThis2.kt")
public void testWrongExplicitThis2() throws Exception { public void testWrongExplicitThis2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongExplicitThis2.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/wrongExplicitThis2.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("wrongGetter.kt") @TestMetadata("wrongGetter.kt")
public void testWrongGetter() throws Exception { public void testWrongGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongGetter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/wrongGetter.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("wrongGetter2.kt") @TestMetadata("wrongGetter2.kt")
public void testWrongGetter2() throws Exception { public void testWrongGetter2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongGetter2.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/wrongGetter2.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("wrongSetter.kt") @TestMetadata("wrongSetter.kt")
public void testWrongSetter() throws Exception { public void testWrongSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongSetter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/conflictingExtension/wrongSetter.kt");
doTest(fileName); doTest(fileName);
} }
} }