Remove explicit type intention should not be available on public

This commit is contained in:
Valentin Kipyatkov
2015-05-05 16:22:14 +03:00
parent 2d90ee5cad
commit b0ce16eada
8 changed files with 62 additions and 10 deletions
@@ -75,16 +75,13 @@ public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependen
editor.getCaretModel().moveToOffset(range.getEndOffset()) editor.getCaretModel().moveToOffset(range.getEndOffset())
} }
else { else {
(declaration : PsiElement).deleteChildRange(colon, typeRef) (declaration as PsiElement).deleteChildRange(colon, typeRef)
} }
} }
} }
private fun canOmitType(declaration: JetCallableDeclaration, expression: JetExpression): Boolean { private fun canOmitType(declaration: JetCallableDeclaration, expression: JetExpression): Boolean {
if (declaration.getModifierList()?.hasModifier(JetTokens.OVERRIDE_KEYWORD) ?: false) return true if (!declaration.canRemoveTypeSpecificationByVisibility()) return false
val descriptor = declaration.resolveToDescriptor()
if ((descriptor as? DeclarationDescriptorWithVisibility)?.getVisibility()?.isPublicAPI() ?: false) return false
// Workaround for anonymous objects and similar expressions without resolution scope // 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 // 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 ?.getStatements()?.singleOrNull() as? JetExpression
?: return false ?: 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 scope = scopeExpression.analyze()[BindingContext.RESOLUTION_SCOPE, scopeExpression] ?: return false
val expressionType = expression.analyzeInContext(scope).getType(expression) ?: return false val expressionType = expression.analyzeInContext(scope).getType(expression) ?: return false
return expressionType.isSubtypeOf(declaredType) return expressionType.isSubtypeOf(declaredType)
@@ -39,16 +39,17 @@ import java.util.*
public class RemoveExplicitTypeIntention : JetSelfTargetingIntention<JetCallableDeclaration>(javaClass(), "Remove explicit type specification") { public class RemoveExplicitTypeIntention : JetSelfTargetingIntention<JetCallableDeclaration>(javaClass(), "Remove explicit type specification") {
override fun isApplicableTo(element: JetCallableDeclaration, caretOffset: Int): Boolean { override fun isApplicableTo(element: JetCallableDeclaration, caretOffset: Int): Boolean {
//TODO: check for public API
if (element.getContainingFile() is JetCodeFragment) return false if (element.getContainingFile() is JetCodeFragment) return false
if (element.getTypeReference() == null) return false if (element.getTypeReference() == null) return false
val initializer = (element as? JetWithExpressionInitializer)?.getInitializer() val initializer = (element as? JetWithExpressionInitializer)?.getInitializer()
if (initializer != null && initializer.getTextRange().containsOffset(caretOffset)) return false if (initializer != null && initializer.getTextRange().containsOffset(caretOffset)) return false
if (!element.canRemoveTypeSpecificationByVisibility()) return false
return when (element) { return when (element) {
is JetProperty -> true is JetProperty -> initializer != null
is JetNamedFunction -> !element.hasBlockBody() && element.getBodyExpression() != null is JetNamedFunction -> !element.hasBlockBody() && initializer != null
is JetParameter -> element.isLoopParameter() is JetParameter -> element.isLoopParameter()
else -> false else -> false
} }
@@ -18,15 +18,20 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.JetNodeTypes 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.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze 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.references.JetReference
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
fun JetCallableDeclaration.setType(type: JetType) { fun JetCallableDeclaration.setType(type: JetType) {
if (type.isError()) return if (type.isError()) return
@@ -59,3 +64,10 @@ fun isAutoCreatedItUsage(expression: JetSimpleNameExpression): Boolean {
val target = reference?.resolveToDescriptors(context)?.singleOrNull() as? ValueParameterDescriptor? ?: return false val target = reference?.resolveToDescriptors(context)?.singleOrNull() as? ValueParameterDescriptor? ?: return false
return context[BindingContext.AUTO_CREATED_IT, target] 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
}
@@ -0,0 +1,2 @@
// IS_APPLICABLE: false
public var x: String? = null
@@ -0,0 +1,7 @@
public trait I {
public fun foo(): String
}
public class C : I {
override fun foo(): <caret>String = ""
}
@@ -0,0 +1,7 @@
public trait I {
public fun foo(): String
}
public class C : I {
override fun foo() = ""
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
public trait I {
public val v: String?
}
public trait I1 : I {
override val v: String<caret>
}
@@ -5050,6 +5050,24 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeExplicitType"), Pattern.compile("^(.+)\\.kt$"), true); 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") @TestMetadata("onType.kt")
public void testOnType() throws Exception { public void testOnType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/onType.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitType/onType.kt");