[kotlin] KTIJ-33746 use KotlinProjectStructureProvider to obtain implementing modules

Also shares the code for checking if the expected declaration can be ignored with the FirCallableCompletionContributor

(cherry picked from commit 8fcd7154c5e2965ca8f854f2ecf9dddd3fc03aad)


(cherry picked from commit 16ad25550148d2211131212ce4e690ba1f350502)

IJ-CR-160265

GitOrigin-RevId: 804064f1c723ade28c3e465b83b66df91c2e189a
This commit is contained in:
Frederik Haselmeier
2025-04-11 12:13:53 +02:00
committed by intellij-monorepo-bot
parent db0faeda58
commit 0909b48f67
3 changed files with 42 additions and 21 deletions

View File

@@ -30,6 +30,7 @@
<orderEntry type="module" module-name="intellij.platform.core.impl" />
<orderEntry type="module" module-name="intellij.java.psi" />
<orderEntry type="library" name="kotlinc.analysis-api" level="project" />
<orderEntry type="library" name="kotlinc.analysis-api-platform-interface" level="project" />
<orderEntry type="library" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="module" module-name="kotlin.base.indices" />
<orderEntry type="module" module-name="intellij.platform.indexing" />
@@ -39,7 +40,5 @@
<orderEntry type="module" module-name="kotlin.base.analysis" />
<orderEntry type="module" module-name="kotlin.formatter" />
<orderEntry type="module" module-name="intellij.platform.codeStyle" />
<orderEntry type="module" module-name="kotlin.base.facet" />
<orderEntry type="module" module-name="kotlin.base.util" />
</component>
</module>

View File

@@ -11,15 +11,19 @@ import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiShortNamesCache
import com.intellij.util.Processor
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.KaPlatformInterface
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.components.KaBuiltinTypes
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinProjectStructureProvider
import org.jetbrains.kotlin.analysis.api.projectStructure.KaDanglingFileModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaSourceModule
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.*
import org.jetbrains.kotlin.base.analysis.isExcludedFromAutoImport
import org.jetbrains.kotlin.idea.base.facet.implementingModules
import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
import org.jetbrains.kotlin.idea.base.util.module
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.isMultiPlatform
@@ -46,7 +50,7 @@ class KtSymbolFromIndexProvider(
return true
}
if (isIgnoredExpectDeclaration(file)) {
if (isIgnoredExpectDeclaration()) {
// filter out expect declarations outside of common modules
return false
}
@@ -483,15 +487,42 @@ private fun MutableSet<Name>.createNamesProcessor(
true
}
/**
* Returns whether the module can declare expect declarations that could be implemented by an implementing module.
*/
private fun KaModule.canHaveExpectDeclarations(): Boolean {
if (targetPlatform.isMultiPlatform()) return true
@OptIn(KaPlatformInterface::class)
val contextModule = (this as? KaDanglingFileModule)?.contextModule ?: this
// We return true in this case out of caution, because we do not know for sure.
if (contextModule !is KaSourceModule) return true
// We can assume that only modules that have some implementing module can have expect declarations because otherwise
// they do not make sense.
return KotlinProjectStructureProvider.getInstance(project)
.getImplementingModules(contextModule)
.isNotEmpty()
}
/**
* We ignore expect declarations within completion in leaf modules because they will already be filled by their (more relevant)
* actual counterpart.
*/
context(KaSession)
private fun KtDeclaration.isIgnoredExpectDeclaration(contextFile: KtFile): Boolean {
@ApiStatus.Internal
fun KaDeclarationSymbol.isIgnoredExpectDeclaration(): Boolean {
if (!isExpect) return false
return !useSiteModule.canHaveExpectDeclarations()
}
/**
* See [KaDeclarationSymbol.isIgnoredExpectDeclaration].
*/
context(KaSession)
@ApiStatus.Internal
fun KtDeclaration.isIgnoredExpectDeclaration(): Boolean {
if (!isExpectDeclaration()) return false
// Modules that have multiple targetPlatforms might have expect declarations without actuals in libraries, so we cannot ignore them.
if (useSiteModule.targetPlatform.isMultiPlatform()) return false
// We can only safely ignore expect declarations if we are in a leaf module without implementing modules.
return contextFile.module?.implementingModules?.isEmpty() == true
return !useSiteModule.canHaveExpectDeclarations()
}

View File

@@ -22,13 +22,8 @@ import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KaErrorType
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability
import org.jetbrains.kotlin.idea.base.analysis.api.utils.collectReceiverTypesForExplicitReceiverExpression
import org.jetbrains.kotlin.idea.base.analysis.api.utils.isJavaSourceOrLibrary
import org.jetbrains.kotlin.idea.base.analysis.api.utils.isPossiblySubTypeOf
import org.jetbrains.kotlin.idea.base.analysis.api.utils.resolveToExpandedSymbol
import org.jetbrains.kotlin.idea.base.facet.implementingModules
import org.jetbrains.kotlin.idea.base.analysis.api.utils.*
import org.jetbrains.kotlin.idea.base.psi.isInsideAnnotationEntryArgumentList
import org.jetbrains.kotlin.idea.base.util.module
import org.jetbrains.kotlin.idea.codeinsight.utils.canBeUsedAsExtension
import org.jetbrains.kotlin.idea.codeinsight.utils.isEnum
import org.jetbrains.kotlin.idea.completion.KotlinFirCompletionParameters
@@ -49,7 +44,6 @@ import org.jetbrains.kotlin.idea.util.positionContext.KotlinNameReferencePositio
import org.jetbrains.kotlin.idea.util.positionContext.KotlinSimpleNameReferencePositionContext
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.platform.isMultiPlatform
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.nextSiblingOfSameType
import org.jetbrains.kotlin.resolve.ArrayFqNames
@@ -93,10 +87,7 @@ internal open class FirCallableCompletionContributor(
)
context(KaSession)
protected open fun filter(symbol: KaCallableSymbol): Boolean =
targetPlatform.isMultiPlatform()
|| !symbol.isExpect
|| symbol.psi?.module?.implementingModules?.isNotEmpty() == true
protected open fun filter(symbol: KaCallableSymbol): Boolean = !symbol.isIgnoredExpectDeclaration()
// todo replace with a sealed hierarchy; too many arguments
protected data class CallableWithMetadataForCompletion(