FIR: Reimplement conflicts checker to detect conflicts in different files
also pass correct ScopeSession to checkers fixes some IC tests
This commit is contained in:
+38
-34
@@ -188,9 +188,27 @@ interface FirDeclarationPresenter {
|
||||
append(']')
|
||||
appendRepresentation(it.symbol.classId)
|
||||
}
|
||||
|
||||
fun represent(it: FirConstructor, owner: FirRegularClass) = buildString {
|
||||
append('<')
|
||||
it.typeParameters.forEach {
|
||||
appendRepresentation(it)
|
||||
append(',')
|
||||
}
|
||||
append('>')
|
||||
append('[')
|
||||
append(']')
|
||||
appendRepresentation(owner.symbol.classId)
|
||||
append('(')
|
||||
it.valueParameters.forEach {
|
||||
appendRepresentation(it)
|
||||
append(',')
|
||||
}
|
||||
append(')')
|
||||
}
|
||||
}
|
||||
|
||||
private class FirDefaultDeclarationPresenter : FirDeclarationPresenter
|
||||
internal class FirDefaultDeclarationPresenter : FirDeclarationPresenter
|
||||
|
||||
private val NO_NAME_PROVIDED = Name.special("<no name provided>")
|
||||
|
||||
@@ -209,49 +227,35 @@ private fun FirDeclaration.isCollectable() = when (this) {
|
||||
/**
|
||||
* Collects FirDeclarations for further analysis.
|
||||
*/
|
||||
class FirDeclarationInspector(
|
||||
private val presenter: FirDeclarationPresenter = FirDefaultDeclarationPresenter()
|
||||
open class FirDeclarationInspector(
|
||||
protected val presenter: FirDeclarationPresenter = FirDefaultDeclarationPresenter()
|
||||
) {
|
||||
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirSimpleFunction>>()
|
||||
|
||||
fun collect(declaration: FirDeclaration) {
|
||||
if (!declaration.isCollectable()) {
|
||||
return
|
||||
when {
|
||||
!declaration.isCollectable() -> {}
|
||||
declaration is FirSimpleFunction -> collectFunction(presenter.represent(declaration), declaration)
|
||||
declaration is FirRegularClass -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirTypeAlias -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirProperty -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
}
|
||||
|
||||
if (declaration is FirSimpleFunction) {
|
||||
return collectFunction(declaration)
|
||||
}
|
||||
|
||||
val key = when (declaration) {
|
||||
is FirRegularClass -> presenter.represent(declaration)
|
||||
is FirTypeAlias -> presenter.represent(declaration)
|
||||
is FirProperty -> presenter.represent(declaration)
|
||||
else -> return
|
||||
}
|
||||
|
||||
var value = otherDeclarations[key]
|
||||
|
||||
if (value == null) {
|
||||
value = mutableListOf()
|
||||
otherDeclarations[key] = value
|
||||
}
|
||||
|
||||
value.add(declaration)
|
||||
}
|
||||
|
||||
private fun collectFunction(declaration: FirSimpleFunction) {
|
||||
val key = presenter.represent(declaration)
|
||||
var value = functionDeclarations[key]
|
||||
|
||||
if (value == null) {
|
||||
value = mutableListOf()
|
||||
functionDeclarations[key] = value
|
||||
protected open fun collectNonFunctionDeclaration(key: String, declaration: FirDeclaration): MutableList<FirDeclaration> =
|
||||
otherDeclarations.getOrPut(key) {
|
||||
mutableListOf()
|
||||
}.also {
|
||||
it.add(declaration)
|
||||
}
|
||||
|
||||
value.add(declaration)
|
||||
}
|
||||
protected open fun collectFunction(key: String, declaration: FirSimpleFunction): MutableList<FirSimpleFunction> =
|
||||
functionDeclarations.getOrPut(key) {
|
||||
mutableListOf()
|
||||
}.also {
|
||||
it.add(declaration)
|
||||
}
|
||||
|
||||
fun contains(declaration: FirDeclaration) = when (declaration) {
|
||||
is FirSimpleFunction -> presenter.represent(declaration) in functionDeclarations
|
||||
|
||||
+255
-34
@@ -5,19 +5,208 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSymbolOwner
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.lookupTracker
|
||||
import org.jetbrains.kotlin.fir.resolve.firProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.PACKAGE_MEMBER
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
|
||||
object FirConflictsChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
private class DeclarationInspector : FirDeclarationInspector() {
|
||||
|
||||
val declarationConflictingSymbols: HashMap<FirDeclaration, SmartSet<AbstractFirBasedSymbol<*>>> = 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<AbstractFirBasedSymbol<*>>()
|
||||
for (otherDeclaration in conflicting) {
|
||||
if (otherDeclaration is FirSymbolOwner<*>) {
|
||||
if (otherDeclaration != declaration && declaration is FirSymbolOwner<*> &&
|
||||
!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: AbstractFirBasedSymbol<*>,
|
||||
conflictingPresentation: String?,
|
||||
conflictingFile: FirFile?,
|
||||
session: FirSession
|
||||
) {
|
||||
val conflicting = conflictingSymbol.fir as? FirDeclaration ?: return
|
||||
if (declaration.session.moduleInfo != conflicting.session.moduleInfo) return
|
||||
val actualConflictingPresentation = conflictingPresentation ?: presenter.represent(conflicting)
|
||||
if (conflicting == declaration || 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) 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 && !(conflicting is FirSymbolOwner<*> &&
|
||||
session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), null))
|
||||
) {
|
||||
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, _ ->
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (declarationName != null) {
|
||||
session.lookupTracker?.recordLookup(
|
||||
declarationName, containingFile.packageFqName.asString(), declaration.source, containingFile.source
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val inspector = FirDeclarationInspector()
|
||||
val inspector = DeclarationInspector()
|
||||
|
||||
when (declaration) {
|
||||
is FirFile -> checkFile(declaration, inspector, context)
|
||||
@@ -25,48 +214,80 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
|
||||
else -> return
|
||||
}
|
||||
|
||||
inspector.functionDeclarations.forEachNonSingle { it, symbols ->
|
||||
reporter.reportOn(it.source, FirErrors.CONFLICTING_OVERLOADS, symbols, context)
|
||||
}
|
||||
|
||||
inspector.otherDeclarations.forEachNonSingle { it, symbols ->
|
||||
reporter.reportOn(it.source, FirErrors.REDECLARATION, symbols, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map<String, List<FirDeclaration>>.forEachNonSingle(action: (FirDeclaration, Collection<AbstractFirBasedSymbol<*>>) -> Unit) {
|
||||
for (value in values) {
|
||||
if (value.size > 1) {
|
||||
val symbols = value.mapNotNull { (it as? FirSymbolOwner<*>)?.symbol }
|
||||
|
||||
value.forEach {
|
||||
action(it, symbols)
|
||||
inspector.declarationConflictingSymbols.forEach { (declaration, symbols) ->
|
||||
when {
|
||||
symbols.isEmpty() -> {}
|
||||
declaration is FirSimpleFunction || declaration is FirConstructor -> {
|
||||
reporter.reportOn(declaration.source, FirErrors.CONFLICTING_OVERLOADS, symbols, context)
|
||||
}
|
||||
else -> {
|
||||
reporter.reportOn(declaration.source, FirErrors.REDECLARATION, symbols, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFile(file: FirFile, inspector: FirDeclarationInspector, context: CheckerContext) {
|
||||
val lookupTracker = context.session.lookupTracker
|
||||
private fun checkFile(file: FirFile, inspector: DeclarationInspector, context: CheckerContext) {
|
||||
val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
|
||||
FirPackageMemberScope(file.packageFqName, context.sessionHolder.session)
|
||||
}
|
||||
for (topLevelDeclaration in file.declarations) {
|
||||
inspector.collect(topLevelDeclaration)
|
||||
if (lookupTracker != null) {
|
||||
when (topLevelDeclaration) {
|
||||
is FirSimpleFunction -> topLevelDeclaration.name
|
||||
is FirVariable<*> -> topLevelDeclaration.name
|
||||
is FirRegularClass -> topLevelDeclaration.name
|
||||
is FirTypeAlias -> topLevelDeclaration.name
|
||||
else -> null
|
||||
}?.let {
|
||||
lookupTracker.recordLookup(it, file.packageFqName.asString(), topLevelDeclaration.source, file.source)
|
||||
}
|
||||
}
|
||||
inspector.collectWithExternalConflicts(topLevelDeclaration, file, context.session, packageMemberScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkRegularClass(declaration: FirRegularClass, inspector: FirDeclarationInspector) {
|
||||
private fun checkRegularClass(declaration: FirRegularClass, inspector: DeclarationInspector) {
|
||||
for (it in declaration.declarations) {
|
||||
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() {
|
||||
|
||||
data class ClassifierWithFile(
|
||||
val classifier: FirClassLikeSymbol<*>,
|
||||
val file: FirFile?
|
||||
)
|
||||
|
||||
val redeclaredClassifiers = HashMap<ClassId, Set<ClassifierWithFile>>()
|
||||
|
||||
override fun registerClassifierRedeclaration(
|
||||
classId: ClassId,
|
||||
newSymbol: FirClassLikeSymbol<*>, newSymbolFile: FirFile,
|
||||
prevSymbol: FirClassLikeSymbol<*>, prevSymbolFile: FirFile?
|
||||
) {
|
||||
redeclaredClassifiers.merge(
|
||||
classId, linkedSetOf(ClassifierWithFile(newSymbol, newSymbolFile), ClassifierWithFile(prevSymbol, prevSymbolFile))
|
||||
) { a, b -> a + b }
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirDeclaration.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) {}
|
||||
}
|
||||
|
||||
acceptChildren(ClassConstructorVisitor())
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
|
||||
object FirDiagnosticsCollector {
|
||||
fun create(session: FirSession, scopeSession: ScopeSession = ScopeSession()): SimpleDiagnosticsCollector {
|
||||
fun create(session: FirSession, scopeSession: ScopeSession): SimpleDiagnosticsCollector {
|
||||
val collector = SimpleDiagnosticsCollector(session, scopeSession)
|
||||
collector.registerAllComponents()
|
||||
return collector
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.CheckersComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirNameConflictsTracker
|
||||
import org.jetbrains.kotlin.fir.caches.FirCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.FirThreadUnsafeCachesFactory
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionService
|
||||
@@ -61,6 +62,7 @@ fun FirSession.registerResolveComponents(lookupTracker: LookupTracker? = null) {
|
||||
register(FirQualifierResolver::class, FirQualifierResolverImpl(this))
|
||||
register(FirTypeResolver::class, FirTypeResolverImpl(this))
|
||||
register(CheckersComponent::class, CheckersComponent())
|
||||
register(FirNameConflictsTrackerComponent::class, FirNameConflictsTracker())
|
||||
if (lookupTracker != null) {
|
||||
val firFileToPath: (FirSourceElement) -> String = {
|
||||
val psiSource = (it as? FirPsiSourceElement<*>) ?: TODO("Not implemented for non-FirPsiSourceElement")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
abstract class FirNameConflictsTrackerComponent : FirSessionComponent {
|
||||
|
||||
abstract fun registerClassifierRedeclaration(
|
||||
classId: ClassId,
|
||||
newSymbol: FirClassLikeSymbol<*>, newSymbolFile: FirFile,
|
||||
prevSymbol: FirClassLikeSymbol<*>, prevSymbolFile: FirFile?
|
||||
)
|
||||
}
|
||||
|
||||
val FirSession.nameConflictsTracker: FirNameConflictsTrackerComponent? by FirSession.nullableSessionComponentAccessor()
|
||||
+35
-34
@@ -6,12 +6,9 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.providers.impl
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.originalIfFakeOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirProviderInternals
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
@@ -62,7 +59,6 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc
|
||||
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
|
||||
destination += (state.functionMap[CallableId(packageFqName, null, name)] ?: emptyList())
|
||||
destination += (state.propertyMap[CallableId(packageFqName, null, name)] ?: emptyList())
|
||||
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
@@ -83,12 +79,12 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc
|
||||
|
||||
@FirProviderInternals
|
||||
override fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass) {
|
||||
klass.accept(FirRecorder, state to owner.file)
|
||||
klass.accept(FirRecorder, FirRecorderData(state, owner.file, session.nameConflictsTracker))
|
||||
}
|
||||
|
||||
@FirProviderInternals
|
||||
override fun recordGeneratedMember(owner: FirAnnotatedDeclaration, klass: FirDeclaration) {
|
||||
klass.accept(FirRecorder, state to owner.file)
|
||||
klass.accept(FirRecorder, FirRecorderData(state, owner.file, session.nameConflictsTracker))
|
||||
}
|
||||
|
||||
private val FirAnnotatedDeclaration.file: FirFile
|
||||
@@ -101,73 +97,78 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc
|
||||
private fun recordFile(file: FirFile, state: State) {
|
||||
val packageName = file.packageFqName
|
||||
state.fileMap.merge(packageName, listOf(file)) { a, b -> a + b }
|
||||
file.acceptChildren(FirRecorder, state to file)
|
||||
file.acceptChildren(FirRecorder, FirRecorderData(state, file, session.nameConflictsTracker))
|
||||
}
|
||||
|
||||
private class FirRecorderData(
|
||||
val state: State,
|
||||
val file: FirFile,
|
||||
val nameConflictsTracker: FirNameConflictsTrackerComponent?
|
||||
)
|
||||
|
||||
private object FirRecorder : FirDefaultVisitor<Unit, Pair<State, FirFile>>() {
|
||||
override fun visitElement(element: FirElement, data: Pair<State, FirFile>) {}
|
||||
private object FirRecorder : FirDefaultVisitor<Unit, FirRecorderData>() {
|
||||
override fun visitElement(element: FirElement, data: FirRecorderData) {}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass, data: Pair<State, FirFile>) {
|
||||
override fun visitRegularClass(regularClass: FirRegularClass, data: FirRecorderData) {
|
||||
val classId = regularClass.symbol.classId
|
||||
val (state, file) = data
|
||||
state.classifierMap[classId] = regularClass
|
||||
state.classifierContainerFileMap[classId] = file
|
||||
val prevFile = data.state.classifierContainerFileMap.put(classId, data.file)
|
||||
data.state.classifierMap.put(classId, regularClass)?.let {
|
||||
data.nameConflictsTracker?.registerClassifierRedeclaration(classId, regularClass.symbol, data.file, it.symbol, prevFile)
|
||||
}
|
||||
|
||||
if (!classId.isNestedClass && !classId.isLocal) {
|
||||
state.classesInPackage.getOrPut(classId.packageFqName, ::mutableSetOf).add(classId.shortClassName)
|
||||
data.state.classesInPackage.getOrPut(classId.packageFqName, ::mutableSetOf).add(classId.shortClassName)
|
||||
}
|
||||
|
||||
regularClass.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: Pair<State, FirFile>) {
|
||||
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: FirRecorderData) {
|
||||
val classId = typeAlias.symbol.classId
|
||||
val (state, file) = data
|
||||
state.classifierMap[classId] = typeAlias
|
||||
state.classifierContainerFileMap[classId] = file
|
||||
val prevFile = data.state.classifierContainerFileMap.put(classId, data.file)
|
||||
data.state.classifierMap.put(classId, typeAlias)?.let {
|
||||
data.nameConflictsTracker?.registerClassifierRedeclaration(classId, typeAlias.symbol, data.file, it.symbol, prevFile)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPropertyAccessor(
|
||||
propertyAccessor: FirPropertyAccessor,
|
||||
data: Pair<State, FirFile>
|
||||
data: FirRecorderData
|
||||
) {
|
||||
val symbol = propertyAccessor.symbol
|
||||
val (state, file) = data
|
||||
state.callableContainerMap[symbol] = file
|
||||
data.state.callableContainerMap[symbol] = data.file
|
||||
}
|
||||
|
||||
private inline fun <reified D : FirCallableMemberDeclaration<D>, S : FirCallableSymbol<D>> registerCallable(
|
||||
symbol: S,
|
||||
data: Pair<State, FirFile>,
|
||||
data: FirRecorderData,
|
||||
map: MutableMap<CallableId, List<S>>
|
||||
) {
|
||||
val callableId = symbol.callableId
|
||||
val (state, file) = data
|
||||
map.merge(callableId, listOf(symbol)) { a, b -> a + b }
|
||||
state.callableContainerMap[symbol] = file
|
||||
data.state.callableContainerMap[symbol] = data.file
|
||||
}
|
||||
|
||||
override fun visitConstructor(constructor: FirConstructor, data: Pair<State, FirFile>) {
|
||||
override fun visitConstructor(constructor: FirConstructor, data: FirRecorderData) {
|
||||
val symbol = constructor.symbol
|
||||
registerCallable(symbol, data, data.first.constructorMap)
|
||||
registerCallable(symbol, data, data.state.constructorMap)
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Pair<State, FirFile>) {
|
||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: FirRecorderData) {
|
||||
val symbol = simpleFunction.symbol
|
||||
registerCallable(symbol, data, data.first.functionMap)
|
||||
registerCallable(symbol, data, data.state.functionMap)
|
||||
}
|
||||
|
||||
override fun visitProperty(property: FirProperty, data: Pair<State, FirFile>) {
|
||||
override fun visitProperty(property: FirProperty, data: FirRecorderData) {
|
||||
val symbol = property.symbol
|
||||
registerCallable(symbol, data, data.first.propertyMap)
|
||||
registerCallable(symbol, data, data.state.propertyMap)
|
||||
property.getter?.let { visitPropertyAccessor(it, data) }
|
||||
property.setter?.let { visitPropertyAccessor(it, data) }
|
||||
}
|
||||
|
||||
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Pair<State, FirFile>) {
|
||||
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: FirRecorderData) {
|
||||
val symbol = enumEntry.symbol
|
||||
val (state, file) = data
|
||||
state.callableContainerMap[symbol] = file
|
||||
data.state.callableContainerMap[symbol] = data.file
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.name.FqName
|
||||
private val INVISIBLE_DEFAULT_STAR_IMPORT = scopeSessionKey<DefaultImportPriority, FirDefaultStarImportingScope>()
|
||||
private val VISIBLE_DEFAULT_STAR_IMPORT = scopeSessionKey<DefaultImportPriority, FirDefaultStarImportingScope>()
|
||||
private val DEFAULT_SIMPLE_IMPORT = scopeSessionKey<DefaultImportPriority, FirDefaultSimpleImportingScope>()
|
||||
private val PACKAGE_MEMBER = scopeSessionKey<FqName, FirPackageMemberScope>()
|
||||
val PACKAGE_MEMBER = scopeSessionKey<FqName, FirPackageMemberScope>()
|
||||
private val ALL_IMPORTS = scopeSessionKey<FirFile, ListStorageFirScope>()
|
||||
|
||||
private class ListStorageFirScope(val result: List<FirScope>) : FirScope()
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// MODULE: lib
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// WITH_REFLECT
|
||||
|
||||
Vendored
+2
-2
@@ -1,11 +1,11 @@
|
||||
// FILE: f1.kt
|
||||
package test
|
||||
|
||||
class A
|
||||
<!REDECLARATION!>class A<!>
|
||||
class F1
|
||||
|
||||
// FILE: f2.kt
|
||||
package test
|
||||
|
||||
class A
|
||||
<!REDECLARATION!>class A<!>
|
||||
class F2
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
// FILE: test1.kt
|
||||
class A
|
||||
class B(val x: Int) {
|
||||
constructor(x: Int, y: Int): this(x + y)
|
||||
}
|
||||
|
||||
// FILE: test2.kt
|
||||
fun A() {}
|
||||
fun B(x: Int) = x
|
||||
fun B(x: Int, y: Int) = x + y
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: test1.kt
|
||||
class <!CONFLICTING_OVERLOADS!>A<!>
|
||||
class B<!CONFLICTING_OVERLOADS!>(val x: Int)<!> {
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
// FILE: a.kt
|
||||
val a : Int = 1
|
||||
fun f() {
|
||||
<!REDECLARATION!>val a : Int = 1<!>
|
||||
<!CONFLICTING_OVERLOADS!>fun f()<!> {
|
||||
}
|
||||
|
||||
// FILE: b.kt
|
||||
val a : Int = 1
|
||||
fun f() {
|
||||
<!REDECLARATION!>val a : Int = 1<!>
|
||||
<!CONFLICTING_OVERLOADS!>fun f()<!> {
|
||||
}
|
||||
|
||||
+8
-8
@@ -7,8 +7,8 @@ interface B : A
|
||||
private fun validFun() {}
|
||||
private val validVal = 1
|
||||
|
||||
private fun invalidFun0() {}
|
||||
private val invalidProp0 = 1
|
||||
<!CONFLICTING_OVERLOADS!>private fun invalidFun0()<!> {}
|
||||
<!REDECLARATION!>private val invalidProp0 = 1<!>
|
||||
|
||||
// NB invalidFun0 and invalidProp0 are conflicting overloads, since the following is an ambiguity:
|
||||
fun useInvalidFun0() = invalidFun0()
|
||||
@@ -20,7 +20,7 @@ fun useInvalidProp0() = invalidProp0
|
||||
<!CONFLICTING_OVERLOADS!>private fun invalidFun2()<!> {}
|
||||
<!CONFLICTING_OVERLOADS!>public fun invalidFun2()<!> {}
|
||||
|
||||
public fun invalidFun3() {}
|
||||
<!CONFLICTING_OVERLOADS!>public fun invalidFun3()<!> {}
|
||||
|
||||
<!CONFLICTING_OVERLOADS!>private fun invalidFun4()<!> {}
|
||||
<!CONFLICTING_OVERLOADS!>public fun invalidFun4()<!> {}
|
||||
@@ -34,16 +34,16 @@ package a
|
||||
private fun validFun() {}
|
||||
private val validVal = 1
|
||||
|
||||
private fun invalidFun0() {}
|
||||
<!CONFLICTING_OVERLOADS!>private fun invalidFun0()<!> {}
|
||||
|
||||
private val invalidProp0 = 1
|
||||
<!REDECLARATION!>private val invalidProp0 = 1<!>
|
||||
|
||||
internal fun invalidFun3() {}
|
||||
internal fun invalidFun4() {}
|
||||
<!CONFLICTING_OVERLOADS!>internal fun invalidFun3()<!> {}
|
||||
<!CONFLICTING_OVERLOADS!>internal fun invalidFun4()<!> {}
|
||||
|
||||
// FILE: c.kt
|
||||
package a
|
||||
|
||||
public fun invalidFun0() {}
|
||||
|
||||
public val invalidProp0 = 1
|
||||
public val invalidProp0 = 1
|
||||
|
||||
@@ -15,4 +15,4 @@ class Outer {
|
||||
}
|
||||
|
||||
// FILE: file2.kt
|
||||
typealias SomeClass = Any
|
||||
<!REDECLARATION!>typealias SomeClass = Any<!>
|
||||
|
||||
@@ -18,5 +18,5 @@ private val test1co: C.Companion = C
|
||||
private val test2: TA = <!INAPPLICABLE_CANDIDATE!>TA<!>()
|
||||
private val test2co = TA
|
||||
|
||||
private class C
|
||||
private typealias TA = Int
|
||||
<!REDECLARATION!>private class C<!>
|
||||
<!REDECLARATION!>private typealias TA = Int<!>
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.FirControlFlowGraphRenderVisitor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.createAllCompilerResolveProcessors
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
@@ -273,7 +274,7 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
|
||||
}
|
||||
|
||||
private fun createCollector(session: FirSession): AbstractDiagnosticCollector {
|
||||
return FirDiagnosticsCollector.create(session)
|
||||
return FirDiagnosticsCollector.create(session, ScopeSession()) // seems this class is obsolete, so do not care about correctness of the scope session here
|
||||
}
|
||||
|
||||
private fun checkCfgDump(testDataFile: File, firFiles: List<FirFile>) {
|
||||
|
||||
+4
-4
@@ -8,7 +8,7 @@ package testsCase1
|
||||
import libPackageCase1.*
|
||||
import libPackageCase1Explicit.emptyArray
|
||||
|
||||
fun <T> Case1.emptyArray(): Array<T> = TODO()
|
||||
<!CONFLICTING_OVERLOADS!>fun <T> Case1.emptyArray(): Array<T><!> = TODO()
|
||||
|
||||
class Case1(){
|
||||
|
||||
@@ -33,7 +33,7 @@ public fun <T> emptyArray(): Array<T> = TODO()
|
||||
// FILE: LibtestsPack1.kt
|
||||
// TESTCASE NUMBER: 1
|
||||
package testsCase1
|
||||
fun <T> Case1.emptyArray(): Array<T> = TODO()
|
||||
<!CONFLICTING_OVERLOADS!>fun <T> Case1.emptyArray(): Array<T><!> = TODO()
|
||||
|
||||
public fun <T> emptyArray(): Array<T> = TODO()
|
||||
|
||||
@@ -46,7 +46,7 @@ package testsCase2
|
||||
import libPackageCase2.*
|
||||
import libPackageCase2Explicit.emptyArray
|
||||
|
||||
fun <T> Case2.emptyArray(): Array<T> = TODO()
|
||||
<!CONFLICTING_OVERLOADS!>fun <T> Case2.emptyArray(): Array<T><!> = TODO()
|
||||
|
||||
class Case2(){
|
||||
|
||||
@@ -77,6 +77,6 @@ public fun <T> emptyArray(): Array<T> = TODO()
|
||||
// FILE: LibtestsPack2.kt
|
||||
// TESTCASE NUMBER: 2
|
||||
package testsCase2
|
||||
fun <T> Case2.emptyArray(): Array<T> = TODO()
|
||||
<!CONFLICTING_OVERLOADS!>fun <T> Case2.emptyArray(): Array<T><!> = TODO()
|
||||
|
||||
public fun <T> emptyArray(): Array<T> = TODO()
|
||||
|
||||
Vendored
-2
@@ -5,8 +5,6 @@
|
||||
annotation class Ann(val x: Int)
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
class Inv<T>
|
||||
|
||||
fun foo(i: Inv<@Ann(unresolved_reference) String>) {}
|
||||
|
||||
// TESTCASE NUMBER: 2
|
||||
|
||||
Vendored
-2
@@ -2,6 +2,4 @@
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class Ann(val x: Int)
|
||||
|
||||
class Inv<T>
|
||||
|
||||
fun case_1(): Inv<@Ann(unresolved_reference) String> = TODO()
|
||||
|
||||
@@ -183,8 +183,8 @@ fun case_13(x: <!UNRESOLVED_REFERENCE!>otherpackage.Case13?<!>) =
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Can't resolve when expression")!>if ((x == null !is Boolean) !== true) {
|
||||
throw Exception()
|
||||
} else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Symbol not found, for `otherpackage.Case13?`")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Symbol not found, for `otherpackage.Case13?`")!>x<!>.<!AMBIGUITY!>equals<!>(x)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Symbol not found for otherpackage.Case13?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Symbol not found for otherpackage.Case13?")!>x<!>.<!AMBIGUITY!>equals<!>(x)
|
||||
}<!>
|
||||
|
||||
// TESTCASE NUMBER: 14
|
||||
|
||||
Reference in New Issue
Block a user