[FIR] FirDeclarationInspector -> FirDeclarationCollector<T>
Makes more sense when you only want to collect declarations of certain type.
This commit is contained in:
committed by
Space Team
parent
5b9c35de2e
commit
6fa5363cf4
+199
-188
@@ -128,220 +128,231 @@ private fun groupTopLevelByName(declarations: List<FirDeclaration>): Map<Name, D
|
||||
/**
|
||||
* Collects FirDeclarations for further analysis.
|
||||
*/
|
||||
class FirDeclarationInspector(
|
||||
private val context: CheckerContext,
|
||||
class FirDeclarationCollector<D : FirDeclaration>(
|
||||
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) {
|
||||
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
fun FirDeclarationCollector<FirDeclaration>.collectClassMembers(klass: FirRegularClass) {
|
||||
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
|
||||
for (it in klass.declarations) {
|
||||
if (!it.isCollectable()) continue
|
||||
for (it in klass.declarations) {
|
||||
if (!it.isCollectable()) continue
|
||||
|
||||
when (it) {
|
||||
is FirSimpleFunction -> collect(it, FirRedeclarationPresenter.represent(it), functionDeclarations)
|
||||
is FirRegularClass -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirTypeAlias -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirVariable -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
else -> {}
|
||||
}
|
||||
when (it) {
|
||||
is FirSimpleFunction -> collect(it, FirRedeclarationPresenter.represent(it), functionDeclarations)
|
||||
is FirRegularClass -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirTypeAlias -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirVariable -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun collect(declaration: FirDeclaration, representation: String, map: MutableMap<String, MutableList<FirDeclaration>>) {
|
||||
map.getOrPut(representation, ::mutableListOf).also {
|
||||
it.add(declaration)
|
||||
|
||||
val conflicts = SmartSet.create<FirBasedSymbol<*>>()
|
||||
for (otherDeclaration in it) {
|
||||
if (otherDeclaration != declaration && !isOverloadable(declaration, otherDeclaration)) {
|
||||
conflicts.add(otherDeclaration.symbol)
|
||||
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol)
|
||||
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<*>>()
|
||||
for (otherDeclaration in it) {
|
||||
if (otherDeclaration != declaration && !isOverloadable(declaration, otherDeclaration, session)) {
|
||||
conflicts.add(otherDeclaration.symbol)
|
||||
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
declarationConflictingSymbols[declaration] = conflicts
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To check top-level declarations for redeclarations, we check multiple sources (the packageMemberScope's properties, functions
|
||||
* and classifiers), redeclared classifiers from session.nameConflictsTracker and the file's declarations themselves.
|
||||
* To prevent inspecting the same source multiple times, we group the declarations in the file by name and subdivide them into
|
||||
* buckets (the properties of DeclarationGroup).
|
||||
*
|
||||
* Depending on the presence of declarations in the buckets, some checks can be omitted.
|
||||
* E.g., if there are no functions and no classes with constructors in the file, we don't need to inspect functions.
|
||||
*
|
||||
* #### Matrix of possible conflicts between "sources" and "buckets"
|
||||
*
|
||||
* | | simpleFunctions | constructors | classLikes | Properties | extensionProperties |
|
||||
* |-------------------------|-----------------|--------------|------------|------------|---------------------|
|
||||
* | functions | X | X | | | |
|
||||
* | classifiers | | | X | X | |
|
||||
* | constructors of classes | X | | | | |
|
||||
* | properties | | | X | X | X |
|
||||
*/
|
||||
@OptIn(SymbolInternals::class)
|
||||
@Suppress("GrazieInspection")
|
||||
fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) {
|
||||
|
||||
for ((declarationName, group) in groupTopLevelByName(file.declarations)) {
|
||||
val groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty()
|
||||
val groupHasSimpleFunctions = group.simpleFunctions.isNotEmpty()
|
||||
|
||||
fun collect(
|
||||
declarations: List<Pair<FirDeclaration, String>>,
|
||||
conflictingSymbol: FirBasedSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
for ((declaration, declarationPresentation) in declarations) {
|
||||
collectTopLevelConflict(
|
||||
declaration,
|
||||
declarationPresentation,
|
||||
file,
|
||||
conflictingSymbol,
|
||||
conflictingPresentation,
|
||||
conflictingFile
|
||||
)
|
||||
|
||||
session.lookupTracker?.recordLookup(declarationName, file.packageFqName.asString(), declaration.source, file.source)
|
||||
}
|
||||
}
|
||||
|
||||
fun collectFromClassifierSource(
|
||||
conflictingSymbol: FirClassifierSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
collect(group.classLikes, conflictingSymbol, conflictingPresentation, conflictingFile)
|
||||
collect(group.properties, conflictingSymbol, conflictingPresentation, conflictingFile)
|
||||
|
||||
if (groupHasSimpleFunctions) {
|
||||
if (conflictingSymbol !is FirRegularClassSymbol) return
|
||||
if (conflictingSymbol.classKind == ClassKind.OBJECT || conflictingSymbol.classKind == ClassKind.ENUM_ENTRY) return
|
||||
|
||||
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||
|
||||
val classWithSameName = conflictingSymbol.fir
|
||||
classWithSameName.unsubstitutedScope(context).processDeclaredConstructors { constructor ->
|
||||
val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, classWithSameName)
|
||||
collect(group.simpleFunctions, conflictingSymbol = constructor, conflictingPresentation = ctorRepresentation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declarationConflictingSymbols[declaration] = conflicts
|
||||
// Check sources in the order from the table above. Skip the check if all relevant buckets are empty.
|
||||
|
||||
// Function source
|
||||
if (groupHasSimpleFunctions || group.constructors.isNotEmpty()) {
|
||||
packageMemberScope.processFunctionsByName(declarationName) {
|
||||
collect(group.simpleFunctions, it)
|
||||
collect(group.constructors, it)
|
||||
}
|
||||
}
|
||||
|
||||
// Classifier sources, collectForClassifierSource will also check constructors.
|
||||
if (groupHasClassLikesOrProperties || groupHasSimpleFunctions) {
|
||||
// Scope will only return one classifier per name
|
||||
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
||||
collectFromClassifierSource(conflictingSymbol = symbol)
|
||||
}
|
||||
|
||||
// session.nameConflictsTracker will contain more classifiers with the same name.
|
||||
session.nameConflictsTracker?.let { it as? FirNameConflictsTracker }
|
||||
?.redeclaredClassifiers?.get(ClassId(file.packageFqName, declarationName))?.forEach {
|
||||
collectFromClassifierSource(conflictingSymbol = it.classifier, conflictingFile = it.file)
|
||||
}
|
||||
|
||||
// session.nameConflictsTracker doesn't seem to work for LL API for redeclarations in the same file, for this reason
|
||||
// we explicitly check classLikes in the same file, too.
|
||||
for ((classLike, representation) in group.classLikes) {
|
||||
collectFromClassifierSource(classLike.symbol, conflictingPresentation = representation, conflictingFile = file)
|
||||
}
|
||||
}
|
||||
|
||||
// Property source
|
||||
if (groupHasClassLikesOrProperties || group.extensionProperties.isNotEmpty()) {
|
||||
packageMemberScope.processPropertiesByName(declarationName) {
|
||||
collect(group.classLikes, conflictingSymbol = it)
|
||||
collect(group.properties, conflictingSymbol = it)
|
||||
collect(group.extensionProperties, conflictingSymbol = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To check top-level declarations for redeclarations, we check multiple sources (the packageMemberScope's properties, functions
|
||||
* and classifiers), redeclared classifiers from session.nameConflictsTracker and the file's declarations themselves.
|
||||
* To prevent inspecting the same source multiple times, we group the declarations in the file by name and subdivide them into
|
||||
* buckets (the properties of DeclarationGroup).
|
||||
*
|
||||
* Depending on the presence of declarations in the buckets, some checks can be omitted.
|
||||
* E.g., if there are no functions and no classes with constructors in the file, we don't need to inspect functions.
|
||||
*
|
||||
* #### Matrix of possible conflicts between "sources" and "buckets"
|
||||
*
|
||||
* | | simpleFunctions | constructors | classLikes | Properties | extensionProperties |
|
||||
* |-------------------------|-----------------|--------------|------------|------------|---------------------|
|
||||
* | functions | X | X | | | |
|
||||
* | classifiers | | | X | X | |
|
||||
* | constructors of classes | X | | | | |
|
||||
* | properties | | | X | X | X |
|
||||
*/
|
||||
private fun FirDeclarationCollector<FirDeclaration>.collectTopLevelConflict(
|
||||
declaration: FirDeclaration,
|
||||
declarationPresentation: String,
|
||||
containingFile: FirFile,
|
||||
conflictingSymbol: FirBasedSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||
@OptIn(SymbolInternals::class)
|
||||
@Suppress("GrazieInspection")
|
||||
fun collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) {
|
||||
|
||||
for ((declarationName, group) in groupTopLevelByName(file.declarations)) {
|
||||
val groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty()
|
||||
val groupHasSimpleFunctions = group.simpleFunctions.isNotEmpty()
|
||||
|
||||
fun collect(
|
||||
declarations: List<Pair<FirDeclaration, String>>,
|
||||
conflictingSymbol: FirBasedSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
for ((declaration, declarationPresentation) in declarations) {
|
||||
collectTopLevelConflict(
|
||||
declaration,
|
||||
declarationPresentation,
|
||||
file,
|
||||
conflictingSymbol,
|
||||
conflictingPresentation,
|
||||
conflictingFile
|
||||
)
|
||||
|
||||
session.lookupTracker?.recordLookup(declarationName, file.packageFqName.asString(), declaration.source, file.source)
|
||||
}
|
||||
}
|
||||
|
||||
fun collectFromClassifierSource(
|
||||
conflictingSymbol: FirClassifierSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
collect(group.classLikes, conflictingSymbol, conflictingPresentation, conflictingFile)
|
||||
collect(group.properties, conflictingSymbol, conflictingPresentation, conflictingFile)
|
||||
|
||||
if (groupHasSimpleFunctions) {
|
||||
if (conflictingSymbol !is FirRegularClassSymbol) return
|
||||
if (conflictingSymbol.classKind == ClassKind.OBJECT || conflictingSymbol.classKind == ClassKind.ENUM_ENTRY) return
|
||||
|
||||
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||
val classWithSameName = conflictingSymbol.fir
|
||||
classWithSameName.unsubstitutedScope(context).processDeclaredConstructors { constructor ->
|
||||
val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, classWithSameName)
|
||||
collect(group.simpleFunctions, conflictingSymbol = constructor, conflictingPresentation = ctorRepresentation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check sources in the order from the table above. Skip the check if all relevant buckets are empty.
|
||||
|
||||
// Function source
|
||||
if (groupHasSimpleFunctions || group.constructors.isNotEmpty()) {
|
||||
packageMemberScope.processFunctionsByName(declarationName) {
|
||||
collect(group.simpleFunctions, it)
|
||||
collect(group.constructors, it)
|
||||
}
|
||||
}
|
||||
|
||||
// Classifier sources, collectForClassifierSource will also check constructors.
|
||||
if (groupHasClassLikesOrProperties || groupHasSimpleFunctions) {
|
||||
// Scope will only return one classifier per name
|
||||
packageMemberScope.processClassifiersByNameWithSubstitution(declarationName) { symbol, _ ->
|
||||
collectFromClassifierSource(conflictingSymbol = symbol)
|
||||
}
|
||||
|
||||
// session.nameConflictsTracker will contain more classifiers with the same name.
|
||||
session.nameConflictsTracker?.let { it as? FirNameConflictsTracker }
|
||||
?.redeclaredClassifiers?.get(ClassId(file.packageFqName, declarationName))?.forEach {
|
||||
collectFromClassifierSource(conflictingSymbol = it.classifier, conflictingFile = it.file)
|
||||
}
|
||||
|
||||
// session.nameConflictsTracker doesn't seem to work for LL API for redeclarations in the same file, for this reason
|
||||
// we explicitly check classLikes in the same file, too.
|
||||
for ((classLike, representation) in group.classLikes) {
|
||||
collectFromClassifierSource(classLike.symbol, conflictingPresentation = representation, conflictingFile = file)
|
||||
}
|
||||
}
|
||||
|
||||
// Property source
|
||||
if (groupHasClassLikesOrProperties || group.extensionProperties.isNotEmpty()) {
|
||||
packageMemberScope.processPropertiesByName(declarationName) {
|
||||
collect(group.classLikes, conflictingSymbol = it)
|
||||
collect(group.properties, conflictingSymbol = it)
|
||||
collect(group.extensionProperties, conflictingSymbol = it)
|
||||
}
|
||||
}
|
||||
val conflicting = conflictingSymbol.fir
|
||||
if (conflicting == declaration || declaration.moduleData != conflicting.moduleData) return
|
||||
val actualConflictingPresentation = conflictingPresentation ?: FirRedeclarationPresenter.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 (!conflicting.isCollectable()) return
|
||||
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile, session)) return
|
||||
if (
|
||||
conflicting is FirMemberDeclaration &&
|
||||
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
|
||||
) return
|
||||
if (isOverloadable(declaration, conflicting, session)) return
|
||||
|
||||
private fun collectTopLevelConflict(
|
||||
declaration: FirDeclaration,
|
||||
declarationPresentation: String,
|
||||
containingFile: FirFile,
|
||||
conflictingSymbol: FirBasedSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||
@OptIn(SymbolInternals::class)
|
||||
val conflicting = conflictingSymbol.fir
|
||||
if (conflicting == declaration || declaration.moduleData != conflicting.moduleData) return
|
||||
val actualConflictingPresentation = conflictingPresentation ?: FirRedeclarationPresenter.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 (!conflicting.isCollectable()) return
|
||||
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile)) return
|
||||
if (
|
||||
conflicting is FirMemberDeclaration &&
|
||||
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
|
||||
) return
|
||||
if (isOverloadable(declaration, conflicting)) return
|
||||
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
|
||||
}
|
||||
|
||||
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
|
||||
}
|
||||
private fun FirSimpleFunction.representsMainFunctionAllowingConflictingOverloads(session: FirSession): Boolean {
|
||||
if (name != StandardNames.MAIN || !symbol.callableId.isTopLevel || !hasMainFunctionStatus) return false
|
||||
if (receiverParameter != null || typeParameters.isNotEmpty()) return false
|
||||
if (valueParameters.isEmpty()) return true
|
||||
val paramType = valueParameters.singleOrNull()?.returnTypeRef?.coneType?.fullyExpandedType(session) ?: return false
|
||||
if (!paramType.isNonPrimitiveArray) return false
|
||||
val typeArgument = paramType.typeArguments.singleOrNull() as? ConeKotlinTypeProjection ?: return false
|
||||
// only Array<String> and Array<out String> are accepted
|
||||
if (typeArgument !is ConeKotlinType && typeArgument !is ConeKotlinTypeProjectionOut) return false
|
||||
return typeArgument.type.fullyExpandedType(session).isString
|
||||
}
|
||||
|
||||
private fun FirSimpleFunction.representsMainFunctionAllowingConflictingOverloads(): Boolean {
|
||||
if (name != StandardNames.MAIN || !symbol.callableId.isTopLevel || !hasMainFunctionStatus) return false
|
||||
if (receiverParameter != null || typeParameters.isNotEmpty()) return false
|
||||
if (valueParameters.isEmpty()) return true
|
||||
val paramType = valueParameters.singleOrNull()?.returnTypeRef?.coneType?.fullyExpandedType(session) ?: return false
|
||||
if (!paramType.isNonPrimitiveArray) return false
|
||||
val typeArgument = paramType.typeArguments.singleOrNull() as? ConeKotlinTypeProjection ?: return false
|
||||
// only Array<String> and Array<out String> are accepted
|
||||
if (typeArgument !is ConeKotlinType && typeArgument !is ConeKotlinTypeProjectionOut) return false
|
||||
return typeArgument.type.fullyExpandedType(session).isString
|
||||
}
|
||||
private fun areCompatibleMainFunctions(
|
||||
declaration1: FirDeclaration, file1: FirFile,
|
||||
declaration2: FirDeclaration, file2: FirFile?,
|
||||
session: FirSession,
|
||||
) = file1 != file2
|
||||
&& declaration1 is FirSimpleFunction
|
||||
&& declaration2 is FirSimpleFunction
|
||||
&& declaration1.representsMainFunctionAllowingConflictingOverloads(session)
|
||||
&& declaration2.representsMainFunctionAllowingConflictingOverloads(session)
|
||||
|
||||
private fun areCompatibleMainFunctions(
|
||||
declaration1: FirDeclaration, file1: FirFile, declaration2: FirDeclaration, file2: FirFile?,
|
||||
) = file1 != file2
|
||||
&& declaration1 is FirSimpleFunction
|
||||
&& declaration2 is FirSimpleFunction
|
||||
&& declaration1.representsMainFunctionAllowingConflictingOverloads()
|
||||
&& declaration2.representsMainFunctionAllowingConflictingOverloads()
|
||||
private fun isOverloadable(
|
||||
declaration: FirDeclaration,
|
||||
conflicting: FirDeclaration,
|
||||
session: FirSession,
|
||||
): Boolean {
|
||||
if (isExpectAndActual(declaration, conflicting)) return true
|
||||
|
||||
private fun isOverloadable(
|
||||
declaration: FirDeclaration,
|
||||
conflicting: FirDeclaration,
|
||||
): Boolean {
|
||||
if (isExpectAndActual(declaration, conflicting)) return true
|
||||
|
||||
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
|
||||
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
|
||||
if (declarationIsLowPriority != conflictingIsLowPriority) return true
|
||||
|
||||
return declaration is FirCallableDeclaration &&
|
||||
conflicting is FirCallableDeclaration &&
|
||||
session.declarationOverloadabilityHelper.isOverloadable(declaration, conflicting)
|
||||
}
|
||||
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
|
||||
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
|
||||
if (declarationIsLowPriority != conflictingIsLowPriority) return true
|
||||
|
||||
return declaration is FirCallableDeclaration &&
|
||||
conflicting is FirCallableDeclaration &&
|
||||
session.declarationOverloadabilityHelper.isOverloadable(declaration, conflicting)
|
||||
}
|
||||
|
||||
/** Checks for redeclarations of value and type parameters, and local variables. */
|
||||
|
||||
+6
-5
@@ -9,8 +9,10 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
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.collectClassMembers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.collectTopLevel
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
@@ -27,7 +29,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
when (declaration) {
|
||||
is FirFile -> {
|
||||
val inspector = FirDeclarationInspector(context)
|
||||
val inspector = FirDeclarationCollector<FirDeclaration>(context)
|
||||
checkFile(declaration, inspector, context)
|
||||
reportConflicts(reporter, context, inspector.declarationConflictingSymbols)
|
||||
}
|
||||
@@ -35,7 +37,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
if (declaration.source?.kind !is KtFakeSourceElementKind) {
|
||||
checkForLocalRedeclarations(declaration.typeParameters, context, reporter)
|
||||
}
|
||||
val inspector = FirDeclarationInspector(context)
|
||||
val inspector = FirDeclarationCollector<FirDeclaration>(context)
|
||||
inspector.collectClassMembers(declaration)
|
||||
reportConflicts(reporter, context, inspector.declarationConflictingSymbols)
|
||||
}
|
||||
@@ -46,7 +48,6 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
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) {
|
||||
FirPackageMemberScope(file.packageFqName, context.sessionHolder.session)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user