[FIR] Merge DeclarationInspector into FirDeclarationInspector
There is no need of two separated classes
This commit is contained in:
committed by
Space Team
parent
07fd778319
commit
b490130e8e
+220
-14
@@ -6,20 +6,30 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirNameConflictsTracker
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
|
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
|
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.util.ListMultimap
|
import org.jetbrains.kotlin.fir.util.ListMultimap
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides representations for FirElement's.
|
* Provides representations for FirElement's.
|
||||||
@@ -248,11 +258,11 @@ private fun FirDeclaration.isCollectable() = when (this) {
|
|||||||
/**
|
/**
|
||||||
* Collects FirDeclarations for further analysis.
|
* Collects FirDeclarations for further analysis.
|
||||||
*/
|
*/
|
||||||
open class FirDeclarationInspector(
|
class FirDeclarationInspector {
|
||||||
protected val presenter: FirDeclarationPresenter = FirDefaultDeclarationPresenter()
|
val declarationConflictingSymbols: HashMap<FirDeclaration, SmartSet<FirBasedSymbol<*>>> = hashMapOf()
|
||||||
) {
|
private val presenter: FirDeclarationPresenter = FirDefaultDeclarationPresenter()
|
||||||
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
private val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||||
val functionDeclarations = mutableMapOf<String, MutableList<FirSimpleFunction>>()
|
private val functionDeclarations = mutableMapOf<String, MutableList<FirSimpleFunction>>()
|
||||||
|
|
||||||
fun collect(declaration: FirDeclaration) {
|
fun collect(declaration: FirDeclaration) {
|
||||||
when {
|
when {
|
||||||
@@ -264,26 +274,222 @@ open class FirDeclarationInspector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun collectNonFunctionDeclaration(key: String, declaration: FirDeclaration): MutableList<FirDeclaration> =
|
fun collectWithExternalConflicts(
|
||||||
|
declaration: FirDeclaration,
|
||||||
|
containingFile: FirFile,
|
||||||
|
session: FirSession,
|
||||||
|
packageMemberScope: FirPackageMemberScope
|
||||||
|
) {
|
||||||
|
collect(declaration)
|
||||||
|
var declarationName: Name? = null
|
||||||
|
val declarationPresentation = presenter.represent(declaration) ?: return
|
||||||
|
|
||||||
|
when (declaration) {
|
||||||
|
is FirSimpleFunction -> {
|
||||||
|
declarationName = declaration.name
|
||||||
|
if (!declarationName.isSpecial) {
|
||||||
|
packageMemberScope.processFunctionsByName(declarationName) {
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration, declarationPresentation, containingFile, it, null, null, session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
||||||
|
symbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
val classWithSameName = symbol.fir as? FirRegularClass
|
||||||
|
classWithSameName?.onConstructors { constructor ->
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration, declarationPresentation, containingFile,
|
||||||
|
constructor.symbol, presenter.represent(constructor, classWithSameName), null,
|
||||||
|
session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is FirVariable -> {
|
||||||
|
declarationName = declaration.name
|
||||||
|
if (!declarationName.isSpecial) {
|
||||||
|
packageMemberScope.processPropertiesByName(declarationName) {
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration, declarationPresentation, containingFile, it, null, null, session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is FirRegularClass -> {
|
||||||
|
declarationName = declaration.name
|
||||||
|
|
||||||
|
if (!declarationName.isSpecial) {
|
||||||
|
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration, declarationPresentation, containingFile, symbol, null, null, session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
declaration.onConstructors { constructor ->
|
||||||
|
packageMemberScope.processFunctionsByName(declarationName!!) {
|
||||||
|
collectExternalConflict(
|
||||||
|
constructor, presenter.represent(constructor, declaration), containingFile,
|
||||||
|
it, null, null, session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.nameConflictsTracker?.let { it as? FirNameConflictsTracker }
|
||||||
|
?.redeclaredClassifiers?.get(declaration.symbol.classId)?.forEach {
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration,
|
||||||
|
declarationPresentation,
|
||||||
|
containingFile,
|
||||||
|
it.classifier,
|
||||||
|
null,
|
||||||
|
it.file,
|
||||||
|
session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is FirTypeAlias -> {
|
||||||
|
declarationName = declaration.name
|
||||||
|
if (!declarationName.isSpecial) {
|
||||||
|
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration, declarationPresentation, containingFile, symbol, null, null, session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
session.nameConflictsTracker?.let { it as? FirNameConflictsTracker }
|
||||||
|
?.redeclaredClassifiers?.get(declaration.symbol.classId)?.forEach {
|
||||||
|
collectExternalConflict(
|
||||||
|
declaration,
|
||||||
|
declarationPresentation,
|
||||||
|
containingFile,
|
||||||
|
it.classifier,
|
||||||
|
null,
|
||||||
|
it.file,
|
||||||
|
session
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (declarationName != null) {
|
||||||
|
session.lookupTracker?.recordLookup(
|
||||||
|
declarationName, containingFile.packageFqName.asString(), declaration.source, containingFile.source
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectNonFunctionDeclaration(key: String, declaration: FirDeclaration): MutableList<FirDeclaration> =
|
||||||
otherDeclarations.getOrPut(key) {
|
otherDeclarations.getOrPut(key) {
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
}.also {
|
}.also {
|
||||||
it.add(declaration)
|
it.add(declaration)
|
||||||
|
collectLocalConflicts(declaration, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun collectFunction(key: String, declaration: FirSimpleFunction): MutableList<FirSimpleFunction> =
|
private fun collectFunction(key: String, declaration: FirSimpleFunction): MutableList<FirSimpleFunction> =
|
||||||
functionDeclarations.getOrPut(key) {
|
functionDeclarations.getOrPut(key) {
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
}.also {
|
}.also {
|
||||||
it.add(declaration)
|
it.add(declaration)
|
||||||
|
collectLocalConflicts(declaration, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun contains(declaration: FirDeclaration) = when (declaration) {
|
private fun collectLocalConflicts(declaration: FirDeclaration, conflicting: List<FirDeclaration>) {
|
||||||
is FirSimpleFunction -> presenter.represent(declaration) in functionDeclarations
|
val localConflicts = SmartSet.create<FirBasedSymbol<*>>()
|
||||||
is FirRegularClass -> presenter.represent(declaration) in otherDeclarations
|
for (otherDeclaration in conflicting) {
|
||||||
is FirTypeAlias -> presenter.represent(declaration) in otherDeclarations
|
if (otherDeclaration is FirField && otherDeclaration.source?.kind == KtFakeSourceElementKind.ClassDelegationField) {
|
||||||
is FirProperty -> presenter.represent(declaration) in otherDeclarations
|
// class delegation field will be renamed after by the IR backend in a case of a name clash
|
||||||
else -> false
|
continue
|
||||||
|
}
|
||||||
|
if (otherDeclaration != declaration && !isExpectAndActual(declaration, otherDeclaration)) {
|
||||||
|
localConflicts.add(otherDeclaration.symbol)
|
||||||
|
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declarationConflictingSymbols[declaration] = localConflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isExpectAndActual(declaration1: FirDeclaration, declaration2: FirDeclaration): Boolean {
|
||||||
|
if (declaration1 !is FirMemberDeclaration) return false
|
||||||
|
if (declaration2 !is FirMemberDeclaration) return false
|
||||||
|
return (declaration1.status.isExpect && declaration2.status.isActual) ||
|
||||||
|
(declaration1.status.isActual && declaration2.status.isExpect)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun areCompatibleMainFunctions(
|
||||||
|
declaration1: FirDeclaration, file1: FirFile, declaration2: FirDeclaration, file2: FirFile?
|
||||||
|
): Boolean {
|
||||||
|
// TODO: proper main function detector
|
||||||
|
if (declaration1 !is FirSimpleFunction || declaration2 !is FirSimpleFunction) return false
|
||||||
|
if (declaration1.name.asString() != "main" || declaration2.name.asString() != "main") return false
|
||||||
|
return file1 != file2
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectExternalConflict(
|
||||||
|
declaration: FirDeclaration,
|
||||||
|
declarationPresentation: String,
|
||||||
|
containingFile: FirFile,
|
||||||
|
conflictingSymbol: FirBasedSymbol<*>,
|
||||||
|
conflictingPresentation: String?,
|
||||||
|
conflictingFile: FirFile?,
|
||||||
|
session: FirSession
|
||||||
|
) {
|
||||||
|
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
val conflicting = conflictingSymbol.fir
|
||||||
|
if (conflicting == declaration || declaration.moduleData != conflicting.moduleData) return
|
||||||
|
val actualConflictingPresentation = conflictingPresentation ?: presenter.represent(conflicting)
|
||||||
|
if (actualConflictingPresentation != declarationPresentation) return
|
||||||
|
val actualConflictingFile =
|
||||||
|
conflictingFile ?: when (conflictingSymbol) {
|
||||||
|
is FirClassLikeSymbol<*> -> session.firProvider.getFirClassifierContainerFileIfAny(conflictingSymbol)
|
||||||
|
is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(conflictingSymbol)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if (containingFile == actualConflictingFile && conflicting.origin == FirDeclarationOrigin.Precompiled) {
|
||||||
|
return // TODO: rewrite local decls checker to the same logic and then remove the check
|
||||||
|
}
|
||||||
|
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile)) return
|
||||||
|
if (isExpectAndActual(declaration, conflicting)) return
|
||||||
|
if (
|
||||||
|
conflicting is FirMemberDeclaration &&
|
||||||
|
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
|
||||||
|
) return
|
||||||
|
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
|
||||||
|
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
|
||||||
|
if (declarationIsLowPriority != conflictingIsLowPriority) return
|
||||||
|
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirDeclarationPresenter.represent(declaration: FirDeclaration): String? =
|
||||||
|
when (declaration) {
|
||||||
|
is FirSimpleFunction -> represent(declaration)
|
||||||
|
is FirRegularClass -> represent(declaration)
|
||||||
|
is FirTypeAlias -> represent(declaration)
|
||||||
|
is FirProperty -> represent(declaration)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirRegularClass.onConstructors(action: (ctor: FirConstructor) -> Unit) {
|
||||||
|
class ClassConstructorVisitor : FirVisitorVoid() {
|
||||||
|
override fun visitElement(element: FirElement) {}
|
||||||
|
|
||||||
|
override fun visitConstructor(constructor: FirConstructor) {
|
||||||
|
action(constructor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclarationStatus(declarationStatus: FirDeclarationStatus) {}
|
||||||
|
override fun visitRegularClass(regularClass: FirRegularClass) {}
|
||||||
|
override fun visitProperty(property: FirProperty) {}
|
||||||
|
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classKind != ClassKind.OBJECT && classKind != ClassKind.ENUM_ENTRY) {
|
||||||
|
acceptChildren(ClassConstructorVisitor())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-233
@@ -6,234 +6,35 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.FirNameConflictsTrackerComponent
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
|
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkConflictingElements
|
import org.jetbrains.kotlin.fir.analysis.checkers.checkConflictingElements
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.packageFqName
|
||||||
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
|
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.PACKAGE_MEMBER
|
import org.jetbrains.kotlin.fir.scopes.impl.PACKAGE_MEMBER
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.utils.SmartSet
|
|
||||||
|
|
||||||
object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||||
|
|
||||||
private class DeclarationInspector : FirDeclarationInspector() {
|
|
||||||
|
|
||||||
val declarationConflictingSymbols: HashMap<FirDeclaration, SmartSet<FirBasedSymbol<*>>> = hashMapOf()
|
|
||||||
|
|
||||||
override fun collectNonFunctionDeclaration(key: String, declaration: FirDeclaration): MutableList<FirDeclaration> =
|
|
||||||
super.collectNonFunctionDeclaration(key, declaration).also {
|
|
||||||
collectLocalConflicts(declaration, it)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun collectFunction(key: String, declaration: FirSimpleFunction): MutableList<FirSimpleFunction> =
|
|
||||||
super.collectFunction(key, declaration).also {
|
|
||||||
collectLocalConflicts(declaration, it)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectLocalConflicts(declaration: FirDeclaration, conflicting: List<FirDeclaration>) {
|
|
||||||
val localConflicts = SmartSet.create<FirBasedSymbol<*>>()
|
|
||||||
for (otherDeclaration in conflicting) {
|
|
||||||
if (otherDeclaration is FirField && otherDeclaration.source?.kind == KtFakeSourceElementKind.ClassDelegationField) {
|
|
||||||
// class delegation field will be renamed after by the IR backend in a case of a name clash
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (otherDeclaration != declaration && !isExpectAndActual(declaration, otherDeclaration)) {
|
|
||||||
localConflicts.add(otherDeclaration.symbol)
|
|
||||||
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
declarationConflictingSymbols[declaration] = localConflicts
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isExpectAndActual(declaration1: FirDeclaration, declaration2: FirDeclaration): Boolean {
|
|
||||||
if (declaration1 !is FirMemberDeclaration) return false
|
|
||||||
if (declaration2 !is FirMemberDeclaration) return false
|
|
||||||
return (declaration1.status.isExpect && declaration2.status.isActual) ||
|
|
||||||
(declaration1.status.isActual && declaration2.status.isExpect)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun areCompatibleMainFunctions(
|
|
||||||
declaration1: FirDeclaration, file1: FirFile, declaration2: FirDeclaration, file2: FirFile?
|
|
||||||
): Boolean {
|
|
||||||
// TODO: proper main function detector
|
|
||||||
if (declaration1 !is FirSimpleFunction || declaration2 !is FirSimpleFunction) return false
|
|
||||||
if (declaration1.name.asString() != "main" || declaration2.name.asString() != "main") return false
|
|
||||||
return file1 != file2
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectExternalConflict(
|
|
||||||
declaration: FirDeclaration,
|
|
||||||
declarationPresentation: String,
|
|
||||||
containingFile: FirFile,
|
|
||||||
conflictingSymbol: FirBasedSymbol<*>,
|
|
||||||
conflictingPresentation: String?,
|
|
||||||
conflictingFile: FirFile?,
|
|
||||||
session: FirSession
|
|
||||||
) {
|
|
||||||
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
|
||||||
@OptIn(SymbolInternals::class)
|
|
||||||
val conflicting = conflictingSymbol.fir
|
|
||||||
if (conflicting == declaration || declaration.moduleData != conflicting.moduleData) return
|
|
||||||
val actualConflictingPresentation = conflictingPresentation ?: presenter.represent(conflicting)
|
|
||||||
if (actualConflictingPresentation != declarationPresentation) return
|
|
||||||
val actualConflictingFile =
|
|
||||||
conflictingFile ?: when (conflictingSymbol) {
|
|
||||||
is FirClassLikeSymbol<*> -> session.firProvider.getFirClassifierContainerFileIfAny(conflictingSymbol)
|
|
||||||
is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(conflictingSymbol)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
if (containingFile == actualConflictingFile && conflicting.origin == FirDeclarationOrigin.Precompiled) {
|
|
||||||
return // TODO: rewrite local decls checker to the same logic and then remove the check
|
|
||||||
}
|
|
||||||
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile)) return
|
|
||||||
if (isExpectAndActual(declaration, conflicting)) return
|
|
||||||
if (
|
|
||||||
conflicting is FirMemberDeclaration &&
|
|
||||||
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
|
|
||||||
) return
|
|
||||||
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
|
|
||||||
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
|
|
||||||
if (declarationIsLowPriority != conflictingIsLowPriority) return
|
|
||||||
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun collectWithExternalConflicts(
|
|
||||||
declaration: FirDeclaration,
|
|
||||||
containingFile: FirFile,
|
|
||||||
session: FirSession,
|
|
||||||
packageMemberScope: FirPackageMemberScope
|
|
||||||
) {
|
|
||||||
collect(declaration)
|
|
||||||
var declarationName: Name? = null
|
|
||||||
val declarationPresentation = presenter.represent(declaration) ?: return
|
|
||||||
|
|
||||||
when (declaration) {
|
|
||||||
is FirSimpleFunction -> {
|
|
||||||
declarationName = declaration.name
|
|
||||||
if (!declarationName.isSpecial) {
|
|
||||||
packageMemberScope.processFunctionsByName(declarationName) {
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration, declarationPresentation, containingFile, it, null, null, session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
|
||||||
symbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
|
||||||
@OptIn(SymbolInternals::class)
|
|
||||||
val classWithSameName = symbol.fir as? FirRegularClass
|
|
||||||
classWithSameName?.onConstructors { constructor ->
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration, declarationPresentation, containingFile,
|
|
||||||
constructor.symbol, presenter.represent(constructor, classWithSameName), null,
|
|
||||||
session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirVariable -> {
|
|
||||||
declarationName = declaration.name
|
|
||||||
if (!declarationName.isSpecial) {
|
|
||||||
packageMemberScope.processPropertiesByName(declarationName) {
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration, declarationPresentation, containingFile, it, null, null, session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirRegularClass -> {
|
|
||||||
declarationName = declaration.name
|
|
||||||
|
|
||||||
if (!declarationName.isSpecial) {
|
|
||||||
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration, declarationPresentation, containingFile, symbol, null, null, session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
declaration.onConstructors { constructor ->
|
|
||||||
packageMemberScope.processFunctionsByName(declarationName!!) {
|
|
||||||
collectExternalConflict(
|
|
||||||
constructor, presenter.represent(constructor, declaration), containingFile,
|
|
||||||
it, null, null, session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
session.nameConflictsTracker?.let { it as? FirNameConflictsTracker }
|
|
||||||
?.redeclaredClassifiers?.get(declaration.symbol.classId)?.forEach {
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration,
|
|
||||||
declarationPresentation,
|
|
||||||
containingFile,
|
|
||||||
it.classifier,
|
|
||||||
null,
|
|
||||||
it.file,
|
|
||||||
session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirTypeAlias -> {
|
|
||||||
declarationName = declaration.name
|
|
||||||
if (!declarationName.isSpecial) {
|
|
||||||
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration, declarationPresentation, containingFile, symbol, null, null, session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
session.nameConflictsTracker?.let { it as? FirNameConflictsTracker }
|
|
||||||
?.redeclaredClassifiers?.get(declaration.symbol.classId)?.forEach {
|
|
||||||
collectExternalConflict(
|
|
||||||
declaration,
|
|
||||||
declarationPresentation,
|
|
||||||
containingFile,
|
|
||||||
it.classifier,
|
|
||||||
null,
|
|
||||||
it.file,
|
|
||||||
session
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (declarationName != null) {
|
|
||||||
session.lookupTracker?.recordLookup(
|
|
||||||
declarationName, containingFile.packageFqName.asString(), declaration.source, containingFile.source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val inspector: DeclarationInspector?
|
val inspector: FirDeclarationInspector?
|
||||||
|
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is FirFile -> {
|
is FirFile -> {
|
||||||
inspector = DeclarationInspector()
|
inspector = FirDeclarationInspector()
|
||||||
checkFile(declaration, inspector, context)
|
checkFile(declaration, inspector, context)
|
||||||
}
|
}
|
||||||
is FirRegularClass -> {
|
is FirRegularClass -> {
|
||||||
if (declaration.source?.kind !is KtFakeSourceElementKind) {
|
if (declaration.source?.kind !is KtFakeSourceElementKind) {
|
||||||
checkConflictingElements(declaration.typeParameters, context, reporter)
|
checkConflictingElements(declaration.typeParameters, context, reporter)
|
||||||
}
|
}
|
||||||
inspector = DeclarationInspector()
|
inspector = FirDeclarationInspector()
|
||||||
checkRegularClass(declaration, inspector)
|
checkRegularClass(declaration, inspector)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -271,7 +72,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkFile(file: FirFile, inspector: DeclarationInspector, context: CheckerContext) {
|
private fun checkFile(file: FirFile, inspector: FirDeclarationInspector, context: CheckerContext) {
|
||||||
val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
|
val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
|
||||||
FirPackageMemberScope(file.packageFqName, context.sessionHolder.session)
|
FirPackageMemberScope(file.packageFqName, context.sessionHolder.session)
|
||||||
}
|
}
|
||||||
@@ -280,22 +81,13 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkRegularClass(declaration: FirRegularClass, inspector: DeclarationInspector) {
|
private fun checkRegularClass(declaration: FirRegularClass, inspector: FirDeclarationInspector) {
|
||||||
for (it in declaration.declarations) {
|
for (it in declaration.declarations) {
|
||||||
inspector.collect(it)
|
inspector.collect(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirDeclarationPresenter.represent(declaration: FirDeclaration): String? =
|
|
||||||
when (declaration) {
|
|
||||||
is FirSimpleFunction -> represent(declaration)
|
|
||||||
is FirRegularClass -> represent(declaration)
|
|
||||||
is FirTypeAlias -> represent(declaration)
|
|
||||||
is FirProperty -> represent(declaration)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
class FirNameConflictsTracker : FirNameConflictsTrackerComponent() {
|
class FirNameConflictsTracker : FirNameConflictsTrackerComponent() {
|
||||||
|
|
||||||
data class ClassifierWithFile(
|
data class ClassifierWithFile(
|
||||||
@@ -316,22 +108,4 @@ class FirNameConflictsTracker : FirNameConflictsTrackerComponent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirRegularClass.onConstructors(action: (ctor: FirConstructor) -> Unit) {
|
|
||||||
|
|
||||||
class ClassConstructorVisitor : FirVisitorVoid() {
|
|
||||||
override fun visitElement(element: FirElement) {}
|
|
||||||
|
|
||||||
override fun visitConstructor(constructor: FirConstructor) {
|
|
||||||
action(constructor)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclarationStatus(declarationStatus: FirDeclarationStatus) {}
|
|
||||||
override fun visitRegularClass(regularClass: FirRegularClass) {}
|
|
||||||
override fun visitProperty(property: FirProperty) {}
|
|
||||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (classKind != ClassKind.OBJECT && classKind != ClassKind.ENUM_ENTRY) {
|
|
||||||
acceptChildren(ClassConstructorVisitor())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user