From b0ce16eada52cdaba2794c48989bc38add38ab13 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 5 May 2015 16:22:14 +0300 Subject: [PATCH] Remove explicit type intention should not be available on public --- .../ConvertToExpressionBodyIntention.kt | 9 +++------ .../intentions/RemoveExplicitTypeIntention.kt | 7 ++++--- .../jetbrains/kotlin/idea/intentions/Utils.kt | 14 +++++++++++++- .../removeExplicitType/notOnPublic.kt | 2 ++ .../removeExplicitType/onOverride.kt | 7 +++++++ .../removeExplicitType/onOverride.kt.after | 7 +++++++ .../removeExplicitType/onOverrideInTrait.kt | 8 ++++++++ .../intentions/IntentionTestGenerated.java | 18 ++++++++++++++++++ 8 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 idea/testData/intentions/removeExplicitType/notOnPublic.kt create mode 100644 idea/testData/intentions/removeExplicitType/onOverride.kt create mode 100644 idea/testData/intentions/removeExplicitType/onOverride.kt.after create mode 100644 idea/testData/intentions/removeExplicitType/onOverrideInTrait.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt index fe48142ea88..7ffb1cf62d8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt @@ -75,16 +75,13 @@ public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependen editor.getCaretModel().moveToOffset(range.getEndOffset()) } else { - (declaration : PsiElement).deleteChildRange(colon, typeRef) + (declaration as PsiElement).deleteChildRange(colon, typeRef) } } } private fun canOmitType(declaration: JetCallableDeclaration, expression: JetExpression): Boolean { - if (declaration.getModifierList()?.hasModifier(JetTokens.OVERRIDE_KEYWORD) ?: false) return true - - val descriptor = declaration.resolveToDescriptor() - if ((descriptor as? DeclarationDescriptorWithVisibility)?.getVisibility()?.isPublicAPI() ?: false) return false + if (!declaration.canRemoveTypeSpecificationByVisibility()) return false // Workaround for anonymous objects and similar expressions without resolution scope // TODO: This should probably be fixed in front-end so that resolution scope is recorded for anonymous objects as well @@ -92,7 +89,7 @@ public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependen ?.getStatements()?.singleOrNull() as? JetExpression ?: return false - val declaredType = (descriptor as? CallableDescriptor)?.getReturnType() ?: return false + val declaredType = (declaration.resolveToDescriptor() as? CallableDescriptor)?.getReturnType() ?: return false val scope = scopeExpression.analyze()[BindingContext.RESOLUTION_SCOPE, scopeExpression] ?: return false val expressionType = expression.analyzeInContext(scope).getType(expression) ?: return false return expressionType.isSubtypeOf(declaredType) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt index 81497cc9d09..01647b0a3b4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt @@ -39,16 +39,17 @@ import java.util.* public class RemoveExplicitTypeIntention : JetSelfTargetingIntention(javaClass(), "Remove explicit type specification") { override fun isApplicableTo(element: JetCallableDeclaration, caretOffset: Int): Boolean { - //TODO: check for public API if (element.getContainingFile() is JetCodeFragment) return false if (element.getTypeReference() == null) return false val initializer = (element as? JetWithExpressionInitializer)?.getInitializer() if (initializer != null && initializer.getTextRange().containsOffset(caretOffset)) return false + if (!element.canRemoveTypeSpecificationByVisibility()) return false + return when (element) { - is JetProperty -> true - is JetNamedFunction -> !element.hasBlockBody() && element.getBodyExpression() != null + is JetProperty -> initializer != null + is JetNamedFunction -> !element.hasBlockBody() && initializer != null is JetParameter -> element.isLoopParameter() else -> false } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index 00d1baa9a14..882d47d1871 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -18,15 +18,20 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.JetNodeTypes -import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.analyzer.analyzeInContext +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.references.JetReference import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf fun JetCallableDeclaration.setType(type: JetType) { if (type.isError()) return @@ -59,3 +64,10 @@ fun isAutoCreatedItUsage(expression: JetSimpleNameExpression): Boolean { val target = reference?.resolveToDescriptors(context)?.singleOrNull() as? ValueParameterDescriptor? ?: return false return context[BindingContext.AUTO_CREATED_IT, target] } + +fun JetCallableDeclaration.canRemoveTypeSpecificationByVisibility(): Boolean { + val descriptor = resolveToDescriptor() + val isOverride = getModifierList()?.hasModifier(JetTokens.OVERRIDE_KEYWORD) ?: false + if (!isOverride && (descriptor as? DeclarationDescriptorWithVisibility)?.getVisibility()?.isPublicAPI() ?: false) return false + return true +} \ No newline at end of file diff --git a/idea/testData/intentions/removeExplicitType/notOnPublic.kt b/idea/testData/intentions/removeExplicitType/notOnPublic.kt new file mode 100644 index 00000000000..4d2853f726b --- /dev/null +++ b/idea/testData/intentions/removeExplicitType/notOnPublic.kt @@ -0,0 +1,2 @@ +// IS_APPLICABLE: false +public var x: String? = null \ No newline at end of file diff --git a/idea/testData/intentions/removeExplicitType/onOverride.kt b/idea/testData/intentions/removeExplicitType/onOverride.kt new file mode 100644 index 00000000000..0fb5b75c1e8 --- /dev/null +++ b/idea/testData/intentions/removeExplicitType/onOverride.kt @@ -0,0 +1,7 @@ +public trait I { + public fun foo(): String +} + +public class C : I { + override fun foo(): String = "" +} \ No newline at end of file diff --git a/idea/testData/intentions/removeExplicitType/onOverride.kt.after b/idea/testData/intentions/removeExplicitType/onOverride.kt.after new file mode 100644 index 00000000000..a7f04465cfa --- /dev/null +++ b/idea/testData/intentions/removeExplicitType/onOverride.kt.after @@ -0,0 +1,7 @@ +public trait I { + public fun foo(): String +} + +public class C : I { + override fun foo() = "" +} \ No newline at end of file diff --git a/idea/testData/intentions/removeExplicitType/onOverrideInTrait.kt b/idea/testData/intentions/removeExplicitType/onOverrideInTrait.kt new file mode 100644 index 00000000000..111ec79cf3b --- /dev/null +++ b/idea/testData/intentions/removeExplicitType/onOverrideInTrait.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +public trait I { + public val v: String? +} + +public trait I1 : I { + override val v: String +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index db86a38a7d5..825dd7eff20 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -5050,6 +5050,24 @@ public class IntentionTestGenerated extends AbstractIntentionTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeExplicitType"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("notOnPublic.kt") + public void testNotOnPublic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/notOnPublic.kt"); + doTest(fileName); + } + + @TestMetadata("onOverride.kt") + public void testOnOverride() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/onOverride.kt"); + doTest(fileName); + } + + @TestMetadata("onOverrideInTrait.kt") + public void testOnOverrideInTrait() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/onOverrideInTrait.kt"); + doTest(fileName); + } + @TestMetadata("onType.kt") public void testOnType() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/onType.kt");