[Analysis API] KTIJ-23588 Do not ignore calls qualified with objects
^KTIJ-23588 Fixed
This commit is contained in:
+27
-5
@@ -174,7 +174,7 @@ internal class KtFirImportOptimizer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processFunctionCall(functionCall: FirFunctionCall) {
|
private fun processFunctionCall(functionCall: FirFunctionCall) {
|
||||||
if (functionCall.isFullyQualified) return
|
if (functionCall.dispatchedWithoutImport) return
|
||||||
processErrorNameReference(functionCall)
|
processErrorNameReference(functionCall)
|
||||||
|
|
||||||
val referencesByName = functionCall.functionReferenceName ?: return
|
val referencesByName = functionCall.functionReferenceName ?: return
|
||||||
@@ -192,7 +192,7 @@ internal class KtFirImportOptimizer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
|
private fun processPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
|
||||||
if (propertyAccessExpression.isFullyQualified) return
|
if (propertyAccessExpression.dispatchedWithoutImport) return
|
||||||
processErrorNameReference(propertyAccessExpression)
|
processErrorNameReference(propertyAccessExpression)
|
||||||
|
|
||||||
val referencedByName = propertyAccessExpression.propertyReferenceName ?: return
|
val referencedByName = propertyAccessExpression.propertyReferenceName ?: return
|
||||||
@@ -208,7 +208,7 @@ internal class KtFirImportOptimizer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
|
private fun processCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
|
||||||
if (callableReferenceAccess.isFullyQualified) return
|
if (callableReferenceAccess.dispatchedWithoutImport) return
|
||||||
processErrorNameReference(callableReferenceAccess)
|
processErrorNameReference(callableReferenceAccess)
|
||||||
|
|
||||||
val referencedByName = callableReferenceAccess.callableReferenceName ?: return
|
val referencedByName = callableReferenceAccess.callableReferenceName ?: return
|
||||||
@@ -331,8 +331,30 @@ private val FirResolvedTypeRef.resolvedClassId: ClassId?
|
|||||||
return singleClassSymbol?.classId
|
return singleClassSymbol?.classId
|
||||||
}
|
}
|
||||||
|
|
||||||
private val FirQualifiedAccessExpression.isFullyQualified: Boolean
|
private val FirQualifiedAccessExpression.dispatchedWithoutImport: Boolean
|
||||||
get() = explicitReceiver is FirResolvedQualifier
|
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? {
|
private fun KtExpression.getPossiblyQualifiedSimpleNameExpression(): KtSimpleNameExpression? {
|
||||||
return ((this as? KtQualifiedExpression)?.selectorExpression ?: this) as? KtSimpleNameExpression?
|
return ((this as? KtQualifiedExpression)?.selectorExpression ?: this) as? KtSimpleNameExpression?
|
||||||
|
|||||||
+30
@@ -58,6 +58,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedAliasedTypeImport.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unusedFunctionImports.kt")
|
@TestMetadata("unusedFunctionImports.kt")
|
||||||
public void testUnusedFunctionImports() throws Exception {
|
public void testUnusedFunctionImports() throws Exception {
|
||||||
@@ -70,6 +76,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedGenericTypeQualifier.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unusedInvokeOperatorImport.kt")
|
@TestMetadata("unusedInvokeOperatorImport.kt")
|
||||||
public void testUnusedInvokeOperatorImport() throws Exception {
|
public void testUnusedInvokeOperatorImport() throws Exception {
|
||||||
@@ -88,6 +100,18 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedAliasedTypeImport.kt");
|
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
|
@Test
|
||||||
@TestMetadata("usedFunctionImport.kt")
|
@TestMetadata("usedFunctionImport.kt")
|
||||||
public void testUsedFunctionImport() throws Exception {
|
public void testUsedFunctionImport() throws Exception {
|
||||||
@@ -100,6 +124,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiImportOptimizerTestGener
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedGenericTypeQualifier.kt");
|
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
|
@Test
|
||||||
@TestMetadata("usedInvokeOperatorAliasedImport.kt")
|
@TestMetadata("usedInvokeOperatorAliasedImport.kt")
|
||||||
public void testUsedInvokeOperatorAliasedImport() throws Exception {
|
public void testUsedInvokeOperatorAliasedImport() throws Exception {
|
||||||
|
|||||||
+30
@@ -58,6 +58,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedAliasedTypeImport.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unusedFunctionImports.kt")
|
@TestMetadata("unusedFunctionImports.kt")
|
||||||
public void testUnusedFunctionImports() throws Exception {
|
public void testUnusedFunctionImports() throws Exception {
|
||||||
@@ -70,6 +76,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/unusedGenericTypeQualifier.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unusedInvokeOperatorImport.kt")
|
@TestMetadata("unusedInvokeOperatorImport.kt")
|
||||||
public void testUnusedInvokeOperatorImport() throws Exception {
|
public void testUnusedInvokeOperatorImport() throws Exception {
|
||||||
@@ -88,6 +100,18 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedAliasedTypeImport.kt");
|
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
|
@Test
|
||||||
@TestMetadata("usedFunctionImport.kt")
|
@TestMetadata("usedFunctionImport.kt")
|
||||||
public void testUsedFunctionImport() throws Exception {
|
public void testUsedFunctionImport() throws Exception {
|
||||||
@@ -100,6 +124,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiImportOptimizerTe
|
|||||||
runTest("analysis/analysis-api/testData/components/importOptimizer/analyseImports/usedGenericTypeQualifier.kt");
|
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
|
@Test
|
||||||
@TestMetadata("usedInvokeOperatorAliasedImport.kt")
|
@TestMetadata("usedInvokeOperatorAliasedImport.kt")
|
||||||
public void testUsedInvokeOperatorAliasedImport() throws Exception {
|
public void testUsedInvokeOperatorAliasedImport() throws Exception {
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
dependency.Bar.extFun
|
||||||
+19
@@ -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() {}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
dependency.Bar.callable
|
||||||
|
dependency.Bar.function
|
||||||
|
dependency.Bar.property
|
||||||
Vendored
+30
@@ -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() {}
|
||||||
|
}
|
||||||
+17
@@ -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() {}
|
||||||
|
}
|
||||||
+26
@@ -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() {}
|
||||||
Vendored
+19
@@ -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() {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user