[FIR] Implement CONFLICTING_IMPORT diagnostic
This commit is contained in:
+4
@@ -951,6 +951,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val CANNOT_BE_IMPORTED by error<KtSimpleNameExpression>(PositioningStrategy.IMPORT_LAST_NAME) {
|
||||
parameter<Name>("name")
|
||||
}
|
||||
|
||||
val CONFLICTING_IMPORT by error<KtImportDirective>(PositioningStrategy.IMPORT_LAST_NAME) {
|
||||
parameter<Name>("name")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtIfExpression
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
@@ -522,5 +523,6 @@ object FirErrors {
|
||||
val CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON by error1<KtSimpleNameExpression, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||
val PACKAGE_CANNOT_BE_IMPORTED by error0<KtSimpleNameExpression>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||
val CANNOT_BE_IMPORTED by error1<KtSimpleNameExpression, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||
val CONFLICTING_IMPORT by error1<KtImportDirective, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||
|
||||
}
|
||||
|
||||
+52
-5
@@ -6,11 +6,14 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.followAllAlias
|
||||
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.resolve.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
object FirImportsChecker : FirFileChecker() {
|
||||
@@ -24,14 +27,14 @@ object FirImportsChecker : FirFileChecker() {
|
||||
checkCanBeImported(import, context, reporter)
|
||||
}
|
||||
}
|
||||
checkConflictingImports(declaration.imports, context, reporter)
|
||||
}
|
||||
|
||||
private fun checkAllUnderFromEnumEntry(import: FirImport, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val fqName = import.importedFqName ?: return
|
||||
if (fqName.isRoot || fqName.parent().isRoot) return
|
||||
val classId = ClassId.topLevel(fqName.parent())
|
||||
val classSymbol = context.session.symbolProvider.getClassLikeSymbolByFqName(classId) ?: return
|
||||
val classFir = classSymbol.fir as? FirRegularClass ?: return
|
||||
val classFir = classId.resolveToClass(context) ?: return
|
||||
if (classFir.isEnumClass && classFir.collectEnumEntries().any { it.name == fqName.shortName() }) {
|
||||
reporter.reportOn(import.source, FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, classFir.name, context)
|
||||
}
|
||||
@@ -42,12 +45,12 @@ object FirImportsChecker : FirFileChecker() {
|
||||
val importedName = importedFqName.shortName()
|
||||
//empty name come from LT in some erroneous cases
|
||||
if (importedName.isSpecial || importedName.identifier.isEmpty()) return
|
||||
|
||||
val classId = (import as? FirResolvedImport)?.resolvedClassId
|
||||
if (classId != null) {
|
||||
val classSymbol = context.session.symbolProvider.getClassLikeSymbolByFqName(classId) ?: return
|
||||
val classFir = classSymbol.fir as? FirRegularClass ?: return
|
||||
val classFir = classId.resolveToClass(context) ?: return
|
||||
if (classFir.classKind.isSingleton) return
|
||||
|
||||
|
||||
val illegalImport = classFir.declarations.any {
|
||||
it is FirSimpleFunction && !it.isStatic && it.name == importedName ||
|
||||
it is FirProperty && it.name == importedName
|
||||
@@ -65,4 +68,48 @@ object FirImportsChecker : FirFileChecker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkConflictingImports(imports: List<FirImport>, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val interestingImports = imports
|
||||
.filterIsInstance<FirResolvedImport>()
|
||||
.filter { import ->
|
||||
!import.isAllUnder
|
||||
&& import.importedName?.identifierOrNullIfSpecial?.isNotEmpty() == true
|
||||
&& import.resolvesToClass(context)
|
||||
}
|
||||
interestingImports
|
||||
.groupBy { it.aliasName ?: it.importedName!! }
|
||||
.values
|
||||
.filter { it.size > 1 }
|
||||
.forEach { conflicts ->
|
||||
conflicts.forEach {
|
||||
reporter.reportOn(it.source, FirErrors.CONFLICTING_IMPORT, it.importedName!!, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirResolvedImport.resolvesToClass(context: CheckerContext): Boolean {
|
||||
if (resolvedClassId != null) {
|
||||
if (isAllUnder) return true
|
||||
val parentClass = resolvedClassId!!
|
||||
val relativeClassName = this.relativeClassName ?: return false
|
||||
val importedName = this.importedName ?: return false
|
||||
val innerClassId = ClassId(parentClass.packageFqName, relativeClassName.child(importedName), false)
|
||||
return innerClassId.resolveToClass(context) != null
|
||||
} else {
|
||||
val importedFqName = importedFqName ?: return false
|
||||
if (importedFqName.isRoot) return false
|
||||
val importedClassId = ClassId.topLevel(importedFqName)
|
||||
return importedClassId.resolveToClass(context) != null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassId.resolveToClass(context: CheckerContext): FirRegularClass? {
|
||||
val classSymbol = context.session.symbolProvider.getClassLikeSymbolByFqName(this) ?: return null
|
||||
return when (classSymbol) {
|
||||
is FirRegularClassSymbol -> classSymbol.fir
|
||||
is FirTypeAliasSymbol -> classSymbol.fir.followAllAlias(context.session) as? FirRegularClass
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -70,6 +70,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTIO
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_ON_NULLABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONDITION_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_IMPORT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION
|
||||
@@ -1174,6 +1175,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
"Cannot import ''{0}'', functions and properties can be imported only from packages or objects",
|
||||
TO_STRING
|
||||
)
|
||||
map.put(
|
||||
CONFLICTING_IMPORT,
|
||||
"Conflicting import, imported name ''{0}'' is ambiguous",
|
||||
TO_STRING
|
||||
)
|
||||
|
||||
// Extended checkers group
|
||||
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
|
||||
|
||||
Reference in New Issue
Block a user