Improve remove/specify type intentions in Explicit API mode
Do not suggest to remove type for public declarations #KT-38915 Fixed Do not show intention to specify type when corresponding quickfix is available #KT-39026 Fixed
This commit is contained in:
+16
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.checkers
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.config.AnalysisFlags
|
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||||
import org.jetbrains.kotlin.config.ExplicitApiMode
|
import org.jetbrains.kotlin.config.ExplicitApiMode
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||||
@@ -122,5 +123,20 @@ class ExplicitApiDeclarationChecker : DeclarationChecker {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun publicReturnTypeShouldBePresentInApiMode(
|
||||||
|
element: KtCallableDeclaration,
|
||||||
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
|
descriptor: DeclarationDescriptor?
|
||||||
|
): Boolean {
|
||||||
|
val isInApiMode = languageVersionSettings.getFlag(AnalysisFlags.explicitApiMode) != ExplicitApiMode.DISABLED
|
||||||
|
return isInApiMode && returnTypeRequired(
|
||||||
|
element,
|
||||||
|
descriptor,
|
||||||
|
checkForPublicApi = true,
|
||||||
|
checkForInternal = false,
|
||||||
|
checkForPrivate = false
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
@@ -18,6 +20,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.checkers.ExplicitApiDeclarationChecker
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
|
||||||
class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
|
class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
|
||||||
@@ -56,6 +59,12 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
|||||||
|
|
||||||
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
|
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
|
||||||
|
|
||||||
|
if (ExplicitApiDeclarationChecker.publicReturnTypeShouldBePresentInApiMode(
|
||||||
|
element,
|
||||||
|
element.languageVersionSettings,
|
||||||
|
element.resolveToDescriptorIfAny()
|
||||||
|
)
|
||||||
|
) return null
|
||||||
if (!redundantTypeSpecification(element.typeReference, initializer)) return null
|
if (!redundantTypeSpecification(element.typeReference, initializer)) return null
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
@@ -92,4 +101,4 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val KtParameter.isSetterParameter: Boolean get() = (parent.parent as? KtPropertyAccessor)?.isSetter ?: false
|
internal val KtParameter.isSetterParameter: Boolean get() = (parent.parent as? KtPropertyAccessor)?.isSetter ?: false
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
|||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.core.setType
|
import org.jetbrains.kotlin.idea.core.setType
|
||||||
import org.jetbrains.kotlin.idea.core.unquote
|
import org.jetbrains.kotlin.idea.core.unquote
|
||||||
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
@@ -42,6 +43,14 @@ class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDec
|
|||||||
), HighPriorityAction {
|
), HighPriorityAction {
|
||||||
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
|
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
|
||||||
if (!ExplicitApiDeclarationChecker.returnTypeCheckIsApplicable(element)) return null
|
if (!ExplicitApiDeclarationChecker.returnTypeCheckIsApplicable(element)) return null
|
||||||
|
// If ApiMode is on, then this intention duplicates corresponding quickfix for compiler error
|
||||||
|
// and we disable it here.
|
||||||
|
if (ExplicitApiDeclarationChecker.publicReturnTypeShouldBePresentInApiMode(
|
||||||
|
element,
|
||||||
|
element.languageVersionSettings,
|
||||||
|
element.resolveToDescriptorIfAny()
|
||||||
|
)
|
||||||
|
) return null
|
||||||
setTextGetter(
|
setTextGetter(
|
||||||
if (element is KtFunction)
|
if (element is KtFunction)
|
||||||
KotlinBundle.lazyMessage("specify.return.type.explicitly")
|
KotlinBundle.lazyMessage("specify.return.type.explicitly")
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// COMPILER_ARGUMENTS: -Xexplicit-api=strict
|
||||||
|
// IS_APPLICABLE: true
|
||||||
|
|
||||||
|
internal fun foo(): <caret>Int = 42
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// COMPILER_ARGUMENTS: -Xexplicit-api=strict
|
||||||
|
// IS_APPLICABLE: true
|
||||||
|
|
||||||
|
internal fun foo() = 42
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// COMPILER_ARGUMENTS: -Xexplicit-api=strict
|
||||||
|
// IS_APPLICABLE: false
|
||||||
|
|
||||||
|
public fun foo(): <caret>Int = 42
|
||||||
@@ -14417,6 +14417,29 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/intentions/removeExplicitTypeWithApiMode")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class RemoveExplicitTypeWithApiMode extends AbstractIntentionTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInRemoveExplicitTypeWithApiMode() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/removeExplicitTypeWithApiMode"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonPublicFunction.kt")
|
||||||
|
public void testNonPublicFunction() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/removeExplicitTypeWithApiMode/nonPublicFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("publicFunction.kt")
|
||||||
|
public void testPublicFunction() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/removeExplicitTypeWithApiMode/publicFunction.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/intentions/removeForLoopIndices")
|
@TestMetadata("idea/testData/intentions/removeForLoopIndices")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user