[FIR] FirDeclarationInspector -> FirDeclarationCollector<T>

Makes more sense when you only want to collect
declarations of certain type.
This commit is contained in:
Nikolay Lunyak
2023-08-09 11:46:04 +03:00
committed by Space Team
parent 5b9c35de2e
commit 6fa5363cf4
2 changed files with 205 additions and 193 deletions
@@ -128,14 +128,15 @@ private fun groupTopLevelByName(declarations: List<FirDeclaration>): Map<Name, D
/** /**
* Collects FirDeclarations for further analysis. * Collects FirDeclarations for further analysis.
*/ */
class FirDeclarationInspector( class FirDeclarationCollector<D : FirDeclaration>(
private val context: CheckerContext, internal val context: CheckerContext,
) { ) {
private val session: FirSession get() = context.sessionHolder.session internal val session: FirSession get() = context.sessionHolder.session
val declarationConflictingSymbols: HashMap<FirDeclaration, SmartSet<FirBasedSymbol<*>>> = hashMapOf() val declarationConflictingSymbols: HashMap<D, SmartSet<FirBasedSymbol<*>>> = hashMapOf()
}
fun collectClassMembers(klass: FirRegularClass) { fun FirDeclarationCollector<FirDeclaration>.collectClassMembers(klass: FirRegularClass) {
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>() val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
val functionDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>() val functionDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
@@ -156,9 +157,17 @@ class FirDeclarationInspector(
map.getOrPut(representation, ::mutableListOf).also { map.getOrPut(representation, ::mutableListOf).also {
it.add(declaration) it.add(declaration)
private fun <D : FirDeclaration> FirDeclarationCollector<D>.collect(
declaration: D,
representation: String,
map: MutableMap<String, MutableList<D>>,
) {
map.getOrPut(representation, ::mutableListOf).also {
it.add(declaration)
val conflicts = SmartSet.create<FirBasedSymbol<*>>() val conflicts = SmartSet.create<FirBasedSymbol<*>>()
for (otherDeclaration in it) { for (otherDeclaration in it) {
if (otherDeclaration != declaration && !isOverloadable(declaration, otherDeclaration)) { if (otherDeclaration != declaration && !isOverloadable(declaration, otherDeclaration, session)) {
conflicts.add(otherDeclaration.symbol) conflicts.add(otherDeclaration.symbol)
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol) declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol)
} }
@@ -188,7 +197,7 @@ class FirDeclarationInspector(
*/ */
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class)
@Suppress("GrazieInspection") @Suppress("GrazieInspection")
fun collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) { fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) {
for ((declarationName, group) in groupTopLevelByName(file.declarations)) { for ((declarationName, group) in groupTopLevelByName(file.declarations)) {
val groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty() val groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty()
@@ -227,6 +236,7 @@ class FirDeclarationInspector(
if (conflictingSymbol.classKind == ClassKind.OBJECT || conflictingSymbol.classKind == ClassKind.ENUM_ENTRY) return if (conflictingSymbol.classKind == ClassKind.OBJECT || conflictingSymbol.classKind == ClassKind.ENUM_ENTRY) return
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS) conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
val classWithSameName = conflictingSymbol.fir val classWithSameName = conflictingSymbol.fir
classWithSameName.unsubstitutedScope(context).processDeclaredConstructors { constructor -> classWithSameName.unsubstitutedScope(context).processDeclaredConstructors { constructor ->
val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, classWithSameName) val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, classWithSameName)
@@ -276,7 +286,7 @@ class FirDeclarationInspector(
} }
} }
private fun collectTopLevelConflict( private fun FirDeclarationCollector<FirDeclaration>.collectTopLevelConflict(
declaration: FirDeclaration, declaration: FirDeclaration,
declarationPresentation: String, declarationPresentation: String,
containingFile: FirFile, containingFile: FirFile,
@@ -297,17 +307,17 @@ class FirDeclarationInspector(
else -> null else -> null
} }
if (!conflicting.isCollectable()) return if (!conflicting.isCollectable()) return
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile)) return if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile, session)) return
if ( if (
conflicting is FirMemberDeclaration && conflicting is FirMemberDeclaration &&
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null) !session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
) return ) return
if (isOverloadable(declaration, conflicting)) return if (isOverloadable(declaration, conflicting, session)) return
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol) declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
} }
private fun FirSimpleFunction.representsMainFunctionAllowingConflictingOverloads(): Boolean { private fun FirSimpleFunction.representsMainFunctionAllowingConflictingOverloads(session: FirSession): Boolean {
if (name != StandardNames.MAIN || !symbol.callableId.isTopLevel || !hasMainFunctionStatus) return false if (name != StandardNames.MAIN || !symbol.callableId.isTopLevel || !hasMainFunctionStatus) return false
if (receiverParameter != null || typeParameters.isNotEmpty()) return false if (receiverParameter != null || typeParameters.isNotEmpty()) return false
if (valueParameters.isEmpty()) return true if (valueParameters.isEmpty()) return true
@@ -320,16 +330,19 @@ class FirDeclarationInspector(
} }
private fun areCompatibleMainFunctions( private fun areCompatibleMainFunctions(
declaration1: FirDeclaration, file1: FirFile, declaration2: FirDeclaration, file2: FirFile?, declaration1: FirDeclaration, file1: FirFile,
declaration2: FirDeclaration, file2: FirFile?,
session: FirSession,
) = file1 != file2 ) = file1 != file2
&& declaration1 is FirSimpleFunction && declaration1 is FirSimpleFunction
&& declaration2 is FirSimpleFunction && declaration2 is FirSimpleFunction
&& declaration1.representsMainFunctionAllowingConflictingOverloads() && declaration1.representsMainFunctionAllowingConflictingOverloads(session)
&& declaration2.representsMainFunctionAllowingConflictingOverloads() && declaration2.representsMainFunctionAllowingConflictingOverloads(session)
private fun isOverloadable( private fun isOverloadable(
declaration: FirDeclaration, declaration: FirDeclaration,
conflicting: FirDeclaration, conflicting: FirDeclaration,
session: FirSession,
): Boolean { ): Boolean {
if (isExpectAndActual(declaration, conflicting)) return true if (isExpectAndActual(declaration, conflicting)) return true
@@ -342,8 +355,6 @@ class FirDeclarationInspector(
session.declarationOverloadabilityHelper.isOverloadable(declaration, conflicting) session.declarationOverloadabilityHelper.isOverloadable(declaration, conflicting)
} }
}
/** Checks for redeclarations of value and type parameters, and local variables. */ /** Checks for redeclarations of value and type parameters, and local variables. */
fun checkForLocalRedeclarations(elements: List<FirElement>, context: CheckerContext, reporter: DiagnosticReporter) { fun checkForLocalRedeclarations(elements: List<FirElement>, context: CheckerContext, reporter: DiagnosticReporter) {
if (elements.size <= 1) return if (elements.size <= 1) return
@@ -9,8 +9,10 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
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.FirNameConflictsTrackerComponent import org.jetbrains.kotlin.fir.FirNameConflictsTrackerComponent
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationCollector
import org.jetbrains.kotlin.fir.analysis.checkers.checkForLocalRedeclarations import org.jetbrains.kotlin.fir.analysis.checkers.checkForLocalRedeclarations
import org.jetbrains.kotlin.fir.analysis.checkers.collectClassMembers
import org.jetbrains.kotlin.fir.analysis.checkers.collectTopLevel
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.*
@@ -27,7 +29,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
when (declaration) { when (declaration) {
is FirFile -> { is FirFile -> {
val inspector = FirDeclarationInspector(context) val inspector = FirDeclarationCollector<FirDeclaration>(context)
checkFile(declaration, inspector, context) checkFile(declaration, inspector, context)
reportConflicts(reporter, context, inspector.declarationConflictingSymbols) reportConflicts(reporter, context, inspector.declarationConflictingSymbols)
} }
@@ -35,7 +37,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
if (declaration.source?.kind !is KtFakeSourceElementKind) { if (declaration.source?.kind !is KtFakeSourceElementKind) {
checkForLocalRedeclarations(declaration.typeParameters, context, reporter) checkForLocalRedeclarations(declaration.typeParameters, context, reporter)
} }
val inspector = FirDeclarationInspector(context) val inspector = FirDeclarationCollector<FirDeclaration>(context)
inspector.collectClassMembers(declaration) inspector.collectClassMembers(declaration)
reportConflicts(reporter, context, inspector.declarationConflictingSymbols) reportConflicts(reporter, context, inspector.declarationConflictingSymbols)
} }
@@ -46,7 +48,6 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
} }
checkForLocalRedeclarations(declaration.typeParameters, context, reporter) checkForLocalRedeclarations(declaration.typeParameters, context, reporter)
} }
return
} }
} }
} }
@@ -76,7 +77,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
} }
} }
private fun checkFile(file: FirFile, inspector: FirDeclarationInspector, context: CheckerContext) { private fun checkFile(file: FirFile, inspector: FirDeclarationCollector<FirDeclaration>, 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)
} }