Remove explicit type intention should not be available on public
This commit is contained in:
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user