From 8cd704b6db1d3913d0a6f9a6df867022bb06e2cd Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Thu, 29 Apr 2021 16:42:16 +0300 Subject: [PATCH] Exclude public API symbols in explicit mode from unused symbol inspection #KT-41659 Fixed --- .../idea/inspections/UnusedSymbolInspection.kt | 9 ++++++++- .../unusedSymbol/unusedClassExplicitApi.kt | 5 +++++ .../unusedSymbol/unusedExtensionExplicitApi.kt | 4 ++++ .../unusedSymbol/unusedFunctionExplicitApi.kt | 6 ++++++ .../inspections/LocalInspectionTestGenerated.java | 15 +++++++++++++++ 5 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 idea/testData/inspectionsLocal/unusedSymbol/unusedClassExplicitApi.kt create mode 100644 idea/testData/inspectionsLocal/unusedSymbol/unusedExtensionExplicitApi.kt create mode 100644 idea/testData/inspectionsLocal/unusedSymbol/unusedFunctionExplicitApi.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index 72bef5a1d29..9c1bc30f1f3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.config.AnalysisFlags +import org.jetbrains.kotlin.config.ExplicitApiMode import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.project.implementingDescriptors @@ -75,7 +76,9 @@ import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression +import org.jetbrains.kotlin.resolve.checkers.explicitApiEnabled import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi import org.jetbrains.kotlin.resolve.isInlineClass import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -266,6 +269,10 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { // More expensive, resolve-based checks val descriptor = declaration.resolveToDescriptorIfAny() ?: return + if (declaration.languageVersionSettings.explicitApiEnabled + && (descriptor as? DeclarationDescriptorWithVisibility)?.isEffectivelyPublicApi == true) { + return + } if (descriptor is FunctionDescriptor && descriptor.isOperator) return val isCheapEnough = lazy(LazyThreadSafetyMode.NONE) { isCheapEnoughToSearchUsages(declaration) diff --git a/idea/testData/inspectionsLocal/unusedSymbol/unusedClassExplicitApi.kt b/idea/testData/inspectionsLocal/unusedSymbol/unusedClassExplicitApi.kt new file mode 100644 index 00000000000..f19f64c3016 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedSymbol/unusedClassExplicitApi.kt @@ -0,0 +1,5 @@ +// PROBLEM: none +// COMPILER_ARGUMENTS: -Xexplicit-api=strict + +public class X { +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedSymbol/unusedExtensionExplicitApi.kt b/idea/testData/inspectionsLocal/unusedSymbol/unusedExtensionExplicitApi.kt new file mode 100644 index 00000000000..9539a39d971 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedSymbol/unusedExtensionExplicitApi.kt @@ -0,0 +1,4 @@ +// PROBLEM: none +// COMPILER_ARGUMENTS: -Xexplicit-api=strict + +public fun String.baz() {} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedSymbol/unusedFunctionExplicitApi.kt b/idea/testData/inspectionsLocal/unusedSymbol/unusedFunctionExplicitApi.kt new file mode 100644 index 00000000000..b3acf4a01a9 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedSymbol/unusedFunctionExplicitApi.kt @@ -0,0 +1,6 @@ +// PROBLEM: none +// COMPILER_ARGUMENTS: -Xexplicit-api=strict + +public class X { + public fun foo() {} +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 9f282f373b3..dec1909bd56 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -14529,11 +14529,26 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/unusedSymbol/typeAlias.kt"); } + @TestMetadata("unusedClassExplicitApi.kt") + public void testUnusedClassExplicitApi() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedSymbol/unusedClassExplicitApi.kt"); + } + @TestMetadata("unusedEnumEntry.kt") public void testUnusedEnumEntry() throws Exception { runTest("idea/testData/inspectionsLocal/unusedSymbol/unusedEnumEntry.kt"); } + @TestMetadata("unusedExtensionExplicitApi.kt") + public void testUnusedExtensionExplicitApi() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedSymbol/unusedExtensionExplicitApi.kt"); + } + + @TestMetadata("unusedFunctionExplicitApi.kt") + public void testUnusedFunctionExplicitApi() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedSymbol/unusedFunctionExplicitApi.kt"); + } + @TestMetadata("usedEnumFunction.kt") public void testUsedEnumFunction() throws Exception { runTest("idea/testData/inspectionsLocal/unusedSymbol/usedEnumFunction.kt");