[Analysis API] KTIJ-23588 Do not ignore calls qualified with objects

^KTIJ-23588 Fixed
This commit is contained in:
Roman Golyshev
2023-04-21 16:48:46 +02:00
committed by teamcity
parent 0aaaa5b4fa
commit e4390e47cf
13 changed files with 202 additions and 5 deletions
@@ -174,7 +174,7 @@ internal class KtFirImportOptimizer(
}
private fun processFunctionCall(functionCall: FirFunctionCall) {
if (functionCall.isFullyQualified) return
if (functionCall.dispatchedWithoutImport) return
processErrorNameReference(functionCall)
val referencesByName = functionCall.functionReferenceName ?: return
@@ -192,7 +192,7 @@ internal class KtFirImportOptimizer(
}
private fun processPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
if (propertyAccessExpression.isFullyQualified) return
if (propertyAccessExpression.dispatchedWithoutImport) return
processErrorNameReference(propertyAccessExpression)
val referencedByName = propertyAccessExpression.propertyReferenceName ?: return
@@ -208,7 +208,7 @@ internal class KtFirImportOptimizer(
}
private fun processCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
if (callableReferenceAccess.isFullyQualified) return
if (callableReferenceAccess.dispatchedWithoutImport) return
processErrorNameReference(callableReferenceAccess)
val referencedByName = callableReferenceAccess.callableReferenceName ?: return
@@ -331,8 +331,30 @@ private val FirResolvedTypeRef.resolvedClassId: ClassId?
return singleClassSymbol?.classId
}
private val FirQualifiedAccessExpression.isFullyQualified: Boolean
get() = explicitReceiver is FirResolvedQualifier
private val FirQualifiedAccessExpression.dispatchedWithoutImport: Boolean
get() = when {
isQualifiedWithPackage -> true
dispatchReceiver is FirThisReceiverExpression -> true
dispatchReceiver == explicitReceiver -> true
else -> false
}
/**
* Returns `true` if [this] expression is fully-qualified with package name.
* Such expressions definitely do not need any kind of imports.
*
* Examples:
* - `pkg.foo()` - `true`
* - `foo()` - `false`
* - `Obj.foo()` - `false`
* - `pkg.Obj.foo()` - `false`
*/
private val FirQualifiedAccessExpression.isQualifiedWithPackage: Boolean
get() {
val receiver = explicitReceiver
return receiver is FirResolvedQualifier && receiver.relativeClassFqName == null
}
private fun KtExpression.getPossiblyQualifiedSimpleNameExpression(): KtSimpleNameExpression? {
return ((this as? KtQualifiedExpression)?.selectorExpression ?: this) as? KtSimpleNameExpression?
@@ -58,6 +58,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedAliasedTypeImport.kt");
}
@Test
@TestMetadata("unusedExtensionFunctionFromObject_implicitReceiver.kt")
public void testUnusedExtensionFunctionFromObject_implicitReceiver() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedExtensionFunctionFromObject_implicitReceiver.kt");
}
@Test
@TestMetadata("unusedFunctionImports.kt")
public void testUnusedFunctionImports() throws Exception {
@@ -70,6 +76,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedGenericTypeQualifier.kt");
}
@Test
@TestMetadata("unusedImportFromObject.kt")
public void testUnusedImportFromObject() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedImportFromObject.kt");
}
@Test
@TestMetadata("unusedInvokeOperatorImport.kt")
public void testUnusedInvokeOperatorImport() throws Exception {
@@ -88,6 +100,18 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedAliasedTypeImport.kt");
}
@Test
@TestMetadata("usedExtensionFunctionFromObject_implicitReceiver.kt")
public void testUsedExtensionFunctionFromObject_implicitReceiver() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedExtensionFunctionFromObject_implicitReceiver.kt");
}
@Test
@TestMetadata("usedExtensionFunction_objectReceiver.kt")
public void testUsedExtensionFunction_objectReceiver() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedExtensionFunction_objectReceiver.kt");
}
@Test
@TestMetadata("usedFunctionImport.kt")
public void testUsedFunctionImport() throws Exception {
@@ -100,6 +124,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedGenericTypeQualifier.kt");
}
@Test
@TestMetadata("usedImportFromObject.kt")
public void testUsedImportFromObject() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedImportFromObject.kt");
}
@Test
@TestMetadata("usedInvokeOperatorAliasedImport.kt")
public void testUsedInvokeOperatorAliasedImport() throws Exception {
@@ -58,6 +58,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedAliasedTypeImport.kt");
}
@Test
@TestMetadata("unusedExtensionFunctionFromObject_implicitReceiver.kt")
public void testUnusedExtensionFunctionFromObject_implicitReceiver() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedExtensionFunctionFromObject_implicitReceiver.kt");
}
@Test
@TestMetadata("unusedFunctionImports.kt")
public void testUnusedFunctionImports() throws Exception {
@@ -70,6 +76,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedGenericTypeQualifier.kt");
}
@Test
@TestMetadata("unusedImportFromObject.kt")
public void testUnusedImportFromObject() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedImportFromObject.kt");
}
@Test
@TestMetadata("unusedInvokeOperatorImport.kt")
public void testUnusedInvokeOperatorImport() throws Exception {
@@ -88,6 +100,18 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedAliasedTypeImport.kt");
}
@Test
@TestMetadata("usedExtensionFunctionFromObject_implicitReceiver.kt")
public void testUsedExtensionFunctionFromObject_implicitReceiver() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedExtensionFunctionFromObject_implicitReceiver.kt");
}
@Test
@TestMetadata("usedExtensionFunction_objectReceiver.kt")
public void testUsedExtensionFunction_objectReceiver() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedExtensionFunction_objectReceiver.kt");
}
@Test
@TestMetadata("usedFunctionImport.kt")
public void testUsedFunctionImport() throws Exception {
@@ -100,6 +124,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedGenericTypeQualifier.kt");
}
@Test
@TestMetadata("usedImportFromObject.kt")
public void testUsedImportFromObject() throws Exception {
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedImportFromObject.kt");
}
@Test
@TestMetadata("usedInvokeOperatorAliasedImport.kt")
public void testUsedInvokeOperatorAliasedImport() throws Exception {
@@ -0,0 +1,19 @@
// FILE: main.kt
package test
import dependency.Bar.extFun
fun usage() {
with(dependency.Bar) {
with(10) {
extFun()
}
}
}
// FILE: dependency.kt
package dependency
object Bar {
fun Int.extFun() {}
}
@@ -0,0 +1,3 @@
dependency.Bar.callable
dependency.Bar.function
dependency.Bar.property
@@ -0,0 +1,30 @@
// FILE: main.kt
import dependency.Bar.property
import dependency.Bar.function
import dependency.Bar.callable
fun test() {
dependency.Bar.property
dependency.Bar.function()
dependency.Bar::callable
with(dependency.Bar) {
property
function()
::callable
}
val bar = dependency.Bar
bar.property
bar.function()
bar::callable
}
// FILE: dependency.kt
package dependency
object Bar {
val property: Int = 10
fun function() {}
fun callable() {}
}
@@ -0,0 +1,17 @@
// FILE: main.kt
package test
import dependency.Bar.extFun
fun usage() {
with(10) {
extFun()
}
}
// FILE: dependency.kt
package dependency
object Bar {
fun Int.extFun() {}
}
@@ -0,0 +1,26 @@
// FILE: main.kt
package test
import dependency.Bar
import dependency.extFun
import dependency.extVal
import dependency.extCallable
fun usage() {
Bar.extFun()
Bar.extVal
val ref = Bar::extCallable
}
// FILE: dependency.kt
package dependency
object Bar
fun Bar.extFun() {}
val Bar.extVal: Int get() = 10
fun Bar.extCallable() {}
@@ -0,0 +1,19 @@
// FILE: main.kt
import dependency.Bar.property
import dependency.Bar.function
import dependency.Bar.callable
fun test() {
property
function()
::callable
}
// FILE: dependency.kt
package dependency
object Bar {
val property: Int = 10
fun function() {}
fun callable() {}
}