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:
Leonid Startsev
2020-09-08 17:34:53 +03:00
parent 5f0e7c3c3f
commit bc432ecb85
8 changed files with 71 additions and 1 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.ExplicitApiMode
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
@@ -122,5 +123,20 @@ class ExplicitApiDeclarationChecker : DeclarationChecker {
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 org.jetbrains.kotlin.descriptors.FunctionDescriptor
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.getQualifiedTypeArgumentList
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.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.checkers.ExplicitApiDeclarationChecker
import org.jetbrains.kotlin.types.typeUtil.isUnit
class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
@@ -56,6 +59,12 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
if (ExplicitApiDeclarationChecker.publicReturnTypeShouldBePresentInApiMode(
element,
element.languageVersionSettings,
element.resolveToDescriptorIfAny()
)
) return null
if (!redundantTypeSpecification(element.typeReference, initializer)) return null
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.setType
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.application.runWriteAction
import org.jetbrains.kotlin.idea.util.getResolutionScope
@@ -42,6 +43,14 @@ class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDec
), HighPriorityAction {
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
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(
if (element is KtFunction)
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
@@ -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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)