diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt index ba0ae716c55..c2471203dd3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.components.ShortenOption import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.utils.addImportToFile import org.jetbrains.kotlin.analysis.api.fir.utils.computeImportableName +import org.jetbrains.kotlin.analysis.api.impl.barebone.parentsOfType import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken @@ -39,6 +40,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.resolve.transformers.PackageResolutionResult import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.getFunctions @@ -49,8 +51,10 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid -import org.jetbrains.kotlin.analysis.api.impl.barebone.parentsOfType -import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.parentOrNull import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector @@ -229,7 +233,8 @@ private class FirShorteningContext(val firResolveState: FirModuleResolveState) { } private fun createFakeResolvedImport(fqNameToImport: FqName): FirResolvedImport? { - val packageOrClass = resolveToPackageOrClass(firSession.symbolProvider, fqNameToImport) ?: return null + val packageOrClass = + (resolveToPackageOrClass(firSession.symbolProvider, fqNameToImport) as? PackageResolutionResult.PackageOrClass) ?: return null val delegateImport = buildImport { importedFqName = fqNameToImport diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 42501e5c4cd..94984ff1927 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -326,6 +326,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.UNRESOLVED_IMPORT) { firDiagnostic -> + UnresolvedImportImpl( + firDiagnostic.a, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS) { firDiagnostic -> CreatingAnInstanceOfAbstractClassImpl( firDiagnostic as KtPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 332ec13633a..9b97496f54c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -261,6 +261,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val candidates: List } + abstract class UnresolvedImport : KtFirDiagnostic() { + override val diagnosticClass get() = UnresolvedImport::class + abstract val reference: String + } + abstract class CreatingAnInstanceOfAbstractClass : KtFirDiagnostic() { override val diagnosticClass get() = CreatingAnInstanceOfAbstractClass::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 1690cc457bc..5a305ced2b3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -300,6 +300,12 @@ internal class UnresolvedReferenceWrongReceiverImpl( override val token: ValidityToken, ) : KtFirDiagnostic.UnresolvedReferenceWrongReceiver(), KtAbstractFirDiagnostic +internal class UnresolvedImportImpl( + override val reference: String, + override val firDiagnostic: KtPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.UnresolvedImport(), KtAbstractFirDiagnostic + internal class CreatingAnInstanceOfAbstractClassImpl( override val firDiagnostic: KtPsiDiagnostic, override val token: ValidityToken, diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 6c807372206..26377c04699 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -26011,6 +26011,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/overloadStatic.kt"); } + @Test + @TestMetadata("staticFunAndPropertyImport.kt") + public void testStaticFunAndPropertyImport() throws Exception { + runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt"); + } + @Test @TestMetadata("staticFunVsImport.kt") public void testStaticFunVsImport() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 34e95e21a3f..868a168cf2b 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -26011,6 +26011,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/overloadStatic.kt"); } + @Test + @TestMetadata("staticFunAndPropertyImport.kt") + public void testStaticFunAndPropertyImport() throws Exception { + runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt"); + } + @Test @TestMetadata("staticFunVsImport.kt") public void testStaticFunVsImport() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index e7af5bdcbec..f16edb1818f 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -26011,6 +26011,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/overloadStatic.kt"); } + @Test + @TestMetadata("staticFunAndPropertyImport.kt") + public void testStaticFunAndPropertyImport() throws Exception { + runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt"); + } + @Test @TestMetadata("staticFunVsImport.kt") public void testStaticFunVsImport() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index e0e3c9d8b12..885a9fb783a 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -123,6 +123,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val UNRESOLVED_REFERENCE_WRONG_RECEIVER by error { parameter>("candidates") } + val UNRESOLVED_IMPORT by error(PositioningStrategy.IMPORT_LAST_NAME) { + parameter("reference") + } } val CALL_RESOLUTION by object : DiagnosticGroup("Call resolution") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 793fe1b9d63..46c3d3f8bb9 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -149,6 +149,7 @@ object FirErrors { val DEPRECATION_ERROR by error2, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val DEPRECATION by warning2, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val UNRESOLVED_REFERENCE_WRONG_RECEIVER by error1>>() + val UNRESOLVED_IMPORT by error1(SourceElementPositioningStrategies.IMPORT_LAST_NAME) // Call resolution val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceUtils.kt index fb8c76427b0..b75b54d897f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceUtils.kt @@ -10,33 +10,33 @@ import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.* -fun KtSourceElement.getChild(type: IElementType, index: Int = 0, depth: Int = -1): KtSourceElement? { - return getChild(setOf(type), index, depth) +fun KtSourceElement.getChild(type: IElementType, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? { + return getChild(setOf(type), index, depth, reverse) } -fun KtSourceElement.getChild(types: TokenSet, index: Int = 0, depth: Int = -1): KtSourceElement? { - return getChild(types.types.toSet(), index, depth) +fun KtSourceElement.getChild(types: TokenSet, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? { + return getChild(types.types.toSet(), index, depth, reverse) } -fun KtSourceElement.getChild(types: Set, index: Int = 0, depth: Int = -1): KtSourceElement? { +fun KtSourceElement.getChild(types: Set, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? { return when (this) { is KtPsiSourceElement -> { - getChild(types, index, depth) + getChild(types, index, depth, reverse) } is KtLightSourceElement -> { - getChild(types, index, depth) + getChild(types, index, depth, reverse) } else -> null } } -private fun KtPsiSourceElement.getChild(types: Set, index: Int, depth: Int): KtSourceElement? { - val visitor = PsiElementFinderByType(types, index, depth) +private fun KtPsiSourceElement.getChild(types: Set, index: Int, depth: Int, reverse: Boolean): KtSourceElement? { + val visitor = PsiElementFinderByType(types, index, depth, reverse) return visitor.find(psi)?.toKtPsiSourceElement() } -private fun KtLightSourceElement.getChild(types: Set, index: Int, depth: Int): KtSourceElement? { - val visitor = LighterTreeElementFinderByType(treeStructure, types, index, depth) +private fun KtLightSourceElement.getChild(types: Set, index: Int, depth: Int, reverse: Boolean): KtSourceElement? { + val visitor = LighterTreeElementFinderByType(treeStructure, types, index, depth, reverse) val childNode = visitor.find(lighterASTNode) ?: return null return buildChildSourceElement(childNode) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/LighterTreeElementFinderByType.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/LighterTreeElementFinderByType.kt index 91ed3db4edc..4f56db3272a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/LighterTreeElementFinderByType.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/LighterTreeElementFinderByType.kt @@ -14,7 +14,8 @@ class LighterTreeElementFinderByType( private val tree: FlyweightCapableTreeStructure, private var types: Collection, private var index: Int, - private val depth: Int + private val depth: Int, + private val reverse: Boolean, ) { fun find(node: LighterASTNode?): LighterASTNode? { if (node == null) return null @@ -33,7 +34,8 @@ class LighterTreeElementFinderByType( if (currentDepth == depth) return null - for (child in node.getChildren()) { + val children = if (reverse) node.getChildren().asReversed() else node.getChildren() + for (child in children) { val result = visitNode(child, currentDepth + 1) if (result != null) return result } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/PsiElementFinderByType.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/PsiElementFinderByType.kt index 912854ef1c7..eb9cc748ef7 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/PsiElementFinderByType.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/PsiElementFinderByType.kt @@ -12,7 +12,8 @@ import org.jetbrains.kotlin.psi.psiUtil.allChildren class PsiElementFinderByType( private val types: Collection, private var index: Int, - private val depth: Int + private val depth: Int, + private val reverse: Boolean, ) { fun find(root: PsiElement): PsiElement? { return visitElement(root, 0) @@ -30,7 +31,8 @@ class PsiElementFinderByType( if (currentDepth == depth) return null - for (child in element.allChildren) { + val children = if (reverse) element.allChildren.toList().asReversed().iterator() else element.allChildren.iterator() + for (child in children) { val result = visitElement(child, currentDepth + 1) if (result != null) return result } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 8e3c602a4ec..fc2f5aa8e9a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -120,6 +120,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirTopLevelFunctionsChecker, FirTopLevelPropertiesChecker, FirImportsChecker, + FirUnresolvedInMiddleOfImportChecker, ) override val controlFlowAnalyserCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt index 1ba60982bd9..b483c59e81f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt @@ -11,15 +11,14 @@ import org.jetbrains.kotlin.fir.analysis.checkers.collectEnumEntries import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationChecker import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.declarations.FirErrorImport -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.declarations.FirImport -import org.jetbrains.kotlin.fir.declarations.FirResolvedImport +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass import org.jetbrains.kotlin.fir.declarations.utils.isOperator import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope +import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol @@ -63,23 +62,37 @@ object FirImportsChecker : FirFileChecker() { //empty name come from LT in some erroneous cases if (importedName.isSpecial || importedName.identifier.isEmpty()) return - val classId = (import as? FirResolvedImport)?.resolvedParentClassId - if (classId != null) { - val classSymbol = classId.resolveToClass(context) ?: return - if (classSymbol.classKind.isSingleton) return + val symbolProvider = context.session.symbolProvider + val parentClassId = (import as? FirResolvedImport)?.resolvedParentClassId + if (parentClassId != null) { + val parentClassSymbol = parentClassId.resolveToClass(context) ?: return - if (!classSymbol.canBeImported(context, importedName)) { - reporter.reportOn(import.source, FirErrors.CANNOT_BE_IMPORTED, importedName, context) + when (val status = parentClassSymbol.getImportStatusOfCallableMembers(context, importedName)) { + ImportStatus.OK -> return + else -> { + val classId = parentClassSymbol.classId.createNestedClassId(importedName) + if (symbolProvider.getClassLikeSymbolByClassId(classId) != null) return + if (status == ImportStatus.UNRESOLVED) { + reporter.reportOn(import.source, FirErrors.UNRESOLVED_IMPORT, importedName.asString(), context) + } else { + reporter.reportOn(import.source, FirErrors.CANNOT_BE_IMPORTED, importedName, context) + } + } } } else { val importedClassId = ClassId.topLevel(importedFqName) - if (importedClassId.resolveToClass(context) != null - || context.session.symbolProvider.getTopLevelCallableSymbols(importedFqName.parent(), importedName).isNotEmpty() - ) { - return - } - context.session.symbolProvider.getPackage(importedFqName)?.let { - reporter.reportOn(import.source, FirErrors.PACKAGE_CANNOT_BE_IMPORTED, context) + val resolvedToClass = importedClassId.resolveToClass(context) != null + val resolvedToSymbols = symbolProvider.getTopLevelCallableSymbols(importedFqName.parent(), importedName).isNotEmpty() + val resolvedToPackages = symbolProvider.getPackage(importedFqName) != null + when { + resolvedToClass || resolvedToSymbols -> return + resolvedToPackages -> reporter.reportOn(import.source, FirErrors.PACKAGE_CANNOT_BE_IMPORTED, context) + else -> reporter.reportOn( + import.source, + FirErrors.UNRESOLVED_IMPORT, + importedName.asString(), + context, + ) } } } @@ -88,9 +101,9 @@ object FirImportsChecker : FirFileChecker() { val interestingImports = imports .filterIsInstance() .filter { import -> - !import.isAllUnder - && import.importedName?.identifierOrNullIfSpecial?.isNotEmpty() == true - && import.resolvesToClass(context) + !import.isAllUnder && + import.importedName?.identifierOrNullIfSpecial?.isNotEmpty() == true && + import.resolvesToClass(context) } interestingImports .groupBy { it.aliasName ?: it.importedName!! } @@ -160,26 +173,74 @@ object FirImportsChecker : FirFileChecker() { return result } - private fun FirRegularClassSymbol.canBeImported( + private enum class ImportStatus { + OK, + CANNOT_BE_IMPORTED, + UNRESOLVED + } + + @OptIn(SymbolInternals::class) + private fun FirRegularClassSymbol.getImportStatusOfCallableMembers(context: CheckerContext, name: Name): ImportStatus { + return if (classKind.isSingleton) { + getImportStatusOfCallableMembersFromSingleton(context, name) + } else { + getImportStatusOfCallableMembersFromNonSingleton(context, name) + } + } + + private fun FirRegularClassSymbol.getImportStatusOfCallableMembersFromSingleton( context: CheckerContext, - name: Name - ): Boolean { + name: Name, + ): ImportStatus { + // Use declaredMemberScope first because it's faster and it's relatively rare to import members declared from super types. + for (scope in listOf(context.session.declaredMemberScope(this), unsubstitutedScope(context))) { + var found = false + scope.processFunctionsByName(name) { + found = true + } + if (found) return ImportStatus.OK + + scope.processPropertiesByName(name) { + found = true + } + if (found) return ImportStatus.OK + } + return ImportStatus.UNRESOLVED + } + + @OptIn(SymbolInternals::class) + private fun FirRegularClassSymbol.getImportStatusOfCallableMembersFromNonSingleton( + context: CheckerContext, + name: Name, + ): ImportStatus { var hasStatic = false - var hasIllegal = false - val scope = context.session.declaredMemberScope(this) - scope.processFunctionsByName(name) { sym -> - if (sym.isStatic) hasStatic = true - else hasIllegal = true - } - if (hasStatic) return true - if (hasIllegal) return false + var found = false + for (scope in listOfNotNull( + // We first try resolution with declaredMemberScope because it's faster and typically imported members are not from + // super types. + context.session.declaredMemberScope(this), - scope.processPropertiesByName(name) { sym -> - if (sym.isStatic) hasStatic = true - else hasIllegal = true - } + // Next, we try static scope, which can provide static (Java) members from super classes. Note that it's not available + // for pure Kotlin classes. + fir.staticScope(context.sessionHolder), - return hasStatic || !hasIllegal + // Finally, we fallback to unsubstitutedScope to catch all + unsubstitutedScope(context) + )) { + scope.processFunctionsByName(name) { sym -> + if (sym.isStatic) hasStatic = true + found = true + } + if (hasStatic) return ImportStatus.OK + + scope.processPropertiesByName(name) { sym -> + if (sym.isStatic) hasStatic = true + found = true + } + if (hasStatic) return ImportStatus.OK + } + return if (found) ImportStatus.CANNOT_BE_IMPORTED + else ImportStatus.UNRESOLVED } private fun checkDeprecatedImport(import: FirImport, context: CheckerContext, reporter: DiagnosticReporter) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnresolvedInMiddleOfImportChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnresolvedInMiddleOfImportChecker.kt new file mode 100644 index 00000000000..8467db7fcb6 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnresolvedInMiddleOfImportChecker.kt @@ -0,0 +1,95 @@ +/* + * 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.analysis.checkers.syntax + +import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.collectEnumEntries +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.getChild +import org.jetbrains.kotlin.fir.declarations.FirErrorImport +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedParentInImport +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.psi.KtFile + +object FirUnresolvedInMiddleOfImportChecker : FirDeclarationSyntaxChecker() { + override fun checkPsiOrLightTree(element: FirFile, source: KtSourceElement, context: CheckerContext, reporter: DiagnosticReporter) { + for (import in element.imports) { + if (import is FirErrorImport) processErrorImport(import, context, reporter) + } + } + + private fun processErrorImport(import: FirErrorImport, context: CheckerContext, reporter: DiagnosticReporter) { + when (val diagnostic = import.diagnostic) { + is ConeUnresolvedParentInImport -> { + val source = import.source ?: return + var segmentSource: KtSourceElement? = source.dotQualifiedExpression() ?: return + + val symbolProvider = context.session.symbolProvider + val parentClassId = diagnostic.parentClassId + + if (import.isAllUnder && isClassIdPointingToEnumEntry(parentClassId, symbolProvider)) { + // Enum entries cannot be resolved as class so star import of enum falls in here and we treat it as + // CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON + reporter.reportOn( + source, + FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, + parentClassId.shortClassName, + context, + ) + return + } + + // For star import, the PSI structure has one less level of qualified references. Hence we start from 0. Otherwise, we start + // from 1 to skip the last imported name. + var errorSegmentIndexFromLast = if (import.isAllUnder) 0 else 1 + var currentClassId = parentClassId.parentClassId + while (currentClassId != null && symbolProvider.getClassLikeSymbolByClassId(currentClassId) == null) { + currentClassId = currentClassId.parentClassId + errorSegmentIndexFromLast++ + } + // Finds the right segment from the last that causes resolution to fail. Note that FirImportResolveTransformer always create + // an error import with resolvable package segments. That is, the segment corresponding to the outermost class name is where + // resolution failed. + for (i in 1..errorSegmentIndexFromLast) { + segmentSource = segmentSource?.dotQualifiedExpression() + } + val unresolvedSource = segmentSource?.selectorExpression() ?: return + reporter.reportOn( + unresolvedSource, + FirErrors.UNRESOLVED_IMPORT, + parentClassId.getOutermostClassName(), + context, + ) + } + else -> { + } + } + } + + /** + * Gets the short outermost class name. For example, `foo.bar.Foo` -> `Foo`. `foo.bar.Outer.Inner.InnerAgain` -> `Outer`. + */ + private fun ClassId.getOutermostClassName() = relativeClassName.pathSegments().first().asString() + + private fun isClassIdPointingToEnumEntry(classId: ClassId, symbolProvider: FirSymbolProvider): Boolean { + val enumClassId = classId.parentClassId ?: return false + val enumClass = + (symbolProvider.getClassLikeSymbolByClassId(enumClassId) as? FirRegularClassSymbol)?.takeIf { it.isEnumClass } ?: return false + return enumClass.collectEnumEntries().any { it.callableId.callableName == classId.shortClassName } + } + + private fun KtSourceElement.dotQualifiedExpression() = getChild(KtNodeTypes.DOT_QUALIFIED_EXPRESSION, depth = 1) + private fun KtSourceElement.selectorExpression() = getChild(KtNodeTypes.REFERENCE_EXPRESSION, depth = 1, reverse = true) +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 0f516fb5d92..3a68606bf64 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -476,6 +476,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_LATEI import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_NOT_NULL_ASSERTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_SAFE_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNREACHABLE_CODE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_IMPORT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE_WRONG_RECEIVER @@ -578,6 +579,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { NAME_OF_CONTAINING_DECLARATION_OR_FILE ) map.put(UNRESOLVED_REFERENCE, "Unresolved reference: {0}", NULLABLE_STRING) + map.put(UNRESOLVED_IMPORT, "Unresolved reference: {0}", NULLABLE_STRING) // & map.put(UNRESOLVED_LABEL, "Unresolved label") map.put(DESERIALIZATION_ERROR, "Deserialization error") map.put(ERROR_FROM_JAVA_RESOLUTION, "Java resolution error") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 60ced65c505..4c387ad0fec 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -113,6 +113,7 @@ private fun ConeDiagnostic.toKtDiagnostic( is ConeUnderscoreIsReserved -> FirErrors.UNDERSCORE_IS_RESERVED.createOn(this.source) is ConeUnderscoreUsageWithoutBackticks -> FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.createOn(this.source) is ConeAmbiguousSuper -> FirErrors.AMBIGUOUS_SUPER.createOn(source, this.candidateTypes) + is ConeUnresolvedParentInImport -> null // reported in FirUnresolvedImportChecker else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}") } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 8737183a5f5..abf917935b2 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -194,7 +194,12 @@ class DeclarationsConverter( var aliasSource: KtSourceElement? = null importDirective.forEachChildren { when (it.tokenType) { - DOT_QUALIFIED_EXPRESSION, REFERENCE_EXPRESSION -> importedFqName = FqName(it.asText) + REFERENCE_EXPRESSION, DOT_QUALIFIED_EXPRESSION -> { + importedFqName = mutableListOf() + .apply { collectSegments(it) } + .joinToString(".") + .let { FqName(it) } + } MUL -> isAllUnder = true IMPORT_ALIAS -> { val importAlias = convertImportAlias(it) @@ -215,6 +220,18 @@ class DeclarationsConverter( } } + private fun MutableList.collectSegments(expression: LighterASTNode) { + when (expression.tokenType) { + REFERENCE_EXPRESSION -> add(expression.asText) + DOT_QUALIFIED_EXPRESSION -> { + expression.forEachChildren { + collectSegments(it) + } + } + else -> {} + } + } + /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseImportDirectives */ diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt index 230b226ba7d..ae843041b4c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt @@ -13,9 +13,11 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.builder.buildErrorImport import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.lookupTracker import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeImportFromSingleton +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedParentInImport import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol @@ -73,7 +75,13 @@ open class FirImportResolveTransformer protected constructor( get() = true private fun transformImportForFqName(fqName: FqName, delegate: FirImport): FirImport { - val (packageFqName, relativeClassFqName, classSymbol) = resolveToPackageOrClass(symbolProvider, fqName) ?: return delegate + val (packageFqName, relativeClassFqName, classSymbol) = when (val result = resolveToPackageOrClass(symbolProvider, fqName)) { + is PackageResolutionResult.Error -> return buildErrorImport { + this.delegate = delegate + this.diagnostic = result.diagnostic + } + is PackageResolutionResult.PackageOrClass -> result + } val firClass = classSymbol?.fir as? FirRegularClass if (delegate.isAllUnder && firClass?.classKind?.isSingleton == true) { return buildErrorImport { @@ -89,7 +97,7 @@ open class FirImportResolveTransformer protected constructor( } } -fun resolveToPackageOrClass(symbolProvider: FirSymbolProvider, fqName: FqName): PackageOrClass? { +fun resolveToPackageOrClass(symbolProvider: FirSymbolProvider, fqName: FqName): PackageResolutionResult { var currentPackage = fqName val pathSegments = fqName.pathSegments() @@ -102,14 +110,21 @@ fun resolveToPackageOrClass(symbolProvider: FirSymbolProvider, fqName: FqName): prefixSize-- } - if (currentPackage == fqName) return PackageOrClass(currentPackage, null, null) - val relativeClassFqName = - FqName.fromSegments((prefixSize until pathSegments.size).map { pathSegments[it].asString() }) + if (currentPackage == fqName) return PackageResolutionResult.PackageOrClass(currentPackage, null, null) + val relativeClassFqName = FqName.fromSegments((prefixSize until pathSegments.size).map { pathSegments[it].asString() }) val classId = ClassId(currentPackage, relativeClassFqName, false) - val symbol = symbolProvider.getClassLikeSymbolByClassId(classId) ?: return null + val symbol = symbolProvider.getClassLikeSymbolByClassId(classId) ?: return PackageResolutionResult.Error( + ConeUnresolvedParentInImport(classId) + ) - return PackageOrClass(currentPackage, relativeClassFqName, symbol) + return PackageResolutionResult.PackageOrClass(currentPackage, relativeClassFqName, symbol) } -data class PackageOrClass(val packageFqName: FqName, val relativeClassFqName: FqName?, val classSymbol: FirClassLikeSymbol<*>?) +sealed class PackageResolutionResult { + data class PackageOrClass( + val packageFqName: FqName, val relativeClassFqName: FqName?, val classSymbol: FirClassLikeSymbol<*>? + ) : PackageResolutionResult() + + class Error(val diagnostic: ConeDiagnostic) : PackageResolutionResult() +} diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt index b3fb2485b9c..2e6d58835f8 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt @@ -196,6 +196,6 @@ fun ImplicitReceiverValue<*>.asTowerDataElement(): FirTowerDataElement = fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement = FirTowerDataElement(this, implicitReceiver = null, isLocal) -private fun FirClass.staticScope(sessionHolder: SessionHolder) = +fun FirClass.staticScope(sessionHolder: SessionHolder) = scopeProvider.getStaticScope(this, sessionHolder.session, sessionHolder.scopeSession) typealias FirLocalScopes = PersistentList diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt index 58bea198c13..cb3a933b15d 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt @@ -198,6 +198,11 @@ class ConeImportFromSingleton(val name: Name) : ConeDiagnostic { open class ConeUnsupported(override val reason: String, val source: KtSourceElement? = null) : ConeDiagnostic +class ConeUnresolvedParentInImport(val parentClassId: ClassId) : ConeDiagnostic { + override val reason: String + get() = "unresolved import" +} + class ConeUnsupportedDynamicType : ConeUnsupported("Dynamic types are not supported in this context") class ConeDeprecated( diff --git a/compiler/testData/diagnostics/tests/imports/Imports.fir.kt b/compiler/testData/diagnostics/tests/imports/Imports.fir.kt index 91aeeb507e4..b85b896e4a8 100644 --- a/compiler/testData/diagnostics/tests/imports/Imports.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/Imports.fir.kt @@ -7,15 +7,15 @@ import b.ext //extension function import b.value //property import b.C.Companion.bar //function from companion object import b.C.Companion.cValue //property from companion object -import b.constant.fff //function from val -import b.constant.dValue //property from val +import b.constant.fff //function from val +import b.constant.dValue //property from val import b.constant import b.E.Companion.f //val from companion object import smth.illegal -import b.C.smth.illegal -import b.bar.smth -import b.bar.* -import b.unr.unr.unr +import b.C.smth.illegal +import b.bar.smth +import b.bar.* +import b.unr.unr.unr import unr.unr.unr fun test(arg: B) { diff --git a/compiler/testData/diagnostics/tests/imports/WrongImport.fir.kt b/compiler/testData/diagnostics/tests/imports/WrongImport.fir.kt index 18e22675bfb..d0d01f13962 100644 --- a/compiler/testData/diagnostics/tests/imports/WrongImport.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/WrongImport.fir.kt @@ -52,27 +52,27 @@ import a import a.b import a.foo -import a.foo.bar +import a.foo.bar import a.bar -import a.bar.foo +import a.bar.foo import a.B.foo -import a.B.foo.bar +import a.B.foo.bar import a.B.bar -import a.B.bar.foo +import a.B.bar.foo import a.C.foo -import a.C.foo.bar +import a.C.foo.bar import a.C.bar -import a.C.bar.foo +import a.C.bar.foo import a.C.Nested -import a.D.foo -import a.D.foo.bar -import a.D.bar -import a.D.bar.foo +import a.D.foo +import a.D.foo.bar +import a.D.bar +import a.D.bar.foo import a.D.Companion.foo -import a.D.Companion.foo.bar +import a.D.Companion.foo.bar import a.D.Companion.bar -import a.D.Companion.bar.foo +import a.D.Companion.bar.foo diff --git a/compiler/testData/diagnostics/tests/imports/kt13112.fir.kt b/compiler/testData/diagnostics/tests/imports/kt13112.fir.kt index 2443edbe356..c1149a51418 100644 --- a/compiler/testData/diagnostics/tests/imports/kt13112.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/kt13112.fir.kt @@ -18,7 +18,7 @@ interface IInterfaceOutput { package mypackage.nestedpackage -import mypackage.nestedpackage.Bar.Baz +import mypackage.nestedpackage.Bar.Baz import anotherpackage.IInterfaceInput import anotherpackage.IInterfaceOutput @@ -43,4 +43,4 @@ class Bar() : IInterfaceInput, IInterfaceOutput { } -data class Baz(val myField: Int) \ No newline at end of file +data class Baz(val myField: Int) diff --git a/compiler/testData/diagnostics/tests/imports/twoImportLists.fir.kt b/compiler/testData/diagnostics/tests/imports/twoImportLists.fir.kt index 777cfdf83c4..b11a407face 100644 --- a/compiler/testData/diagnostics/tests/imports/twoImportLists.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/twoImportLists.fir.kt @@ -8,15 +8,15 @@ import b.ext //extension function import b.value //property import b.C.Companion.bar //function from companion object import b.C.Companion.cValue //property from companion object -import b.constant.fff //function from val -import b.constant.dValue //property from val +import b.constant.fff //function from val +import b.constant.dValue //property from val import smth.illegal -import b.C.smth.illegal +import b.C.smth.illegal <<<HEAD -import b.bar.smth -import b.bar.* -import b.unr.unr.unr +import b.bar.smth +import b.bar.* +import b.unr.unr.unr import unr.unr.unr import b.constant import b.E.Companion.f //val from companion object diff --git a/compiler/testData/diagnostics/tests/regressions/kt762.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt762.fir.kt index 8409b20d947..7667f2c23d5 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt762.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt762.fir.kt @@ -1,4 +1,4 @@ //KT-762 Wrong highlighting in imports (No errors reported on unresolved imports) -import aaa // must be an error +import aaa // must be an error fun main() {} diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt new file mode 100644 index 00000000000..b022f1d7741 --- /dev/null +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt @@ -0,0 +1,45 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_VARIABLE +// FILE: A.java +public class A { + static void foo() {} + int foo; + + static void foo2() {} + int foo2; + + static int bar; + int bar() {return 1;} + + static int bar2; + int bar2() {return 1;} + + static class quux {} + void quux() {} + int quux; + + static class quux2 {} + void quux2() {} + int quux2; + + static void baz() {} +} + +// FILE: B.java +public class B extends A { + void baz(int i) {} +} + + +// FILE: 1.kt +// Below should be all good because there is always a static function, property, or class with the requested name. +import A.foo +import A.bar +import A.quux +import B.foo2 +import B.bar2 +import A.baz +import B.baz + +// class cannot be imported by subclass +import B.quux2 diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.txt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.txt new file mode 100644 index 00000000000..03cd0f4f956 --- /dev/null +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.txt @@ -0,0 +1,61 @@ +package + +public open class A { + public constructor A() + public/*package*/ final var foo: kotlin.Int + public/*package*/ final var foo2: kotlin.Int + public/*package*/ final var quux: kotlin.Int + public/*package*/ final var quux2: kotlin.Int + public/*package*/ open fun bar(): kotlin.Int + public/*package*/ open fun bar2(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open fun quux(): kotlin.Unit + public/*package*/ open fun quux2(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public/*package*/ open class quux { + public/*package*/ constructor quux() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public/*package*/ open class quux2 { + public/*package*/ constructor quux2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + // Static members + public/*package*/ final var bar: kotlin.Int + public/*package*/ final var bar2: kotlin.Int + public/*package*/ open fun baz(): kotlin.Unit + public/*package*/ open fun foo(): kotlin.Unit + public/*package*/ open fun foo2(): kotlin.Unit +} + +public open class B : A { + public constructor B() + public/*package*/ final override /*1*/ /*fake_override*/ var foo: kotlin.Int + public/*package*/ final override /*1*/ /*fake_override*/ var foo2: kotlin.Int + public/*package*/ final override /*1*/ /*fake_override*/ var quux: kotlin.Int + public/*package*/ final override /*1*/ /*fake_override*/ var quux2: kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun bar(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun bar2(): kotlin.Int + public/*package*/ open fun baz(/*0*/ i: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun quux(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun quux2(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final override /*1*/ /*fake_override*/ var bar: kotlin.Int + public/*package*/ final override /*1*/ /*fake_override*/ var bar2: kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun baz(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun foo2(): kotlin.Unit +} + diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.kt index 7deb814c881..eaccfdd5eea 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.kt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.kt @@ -4,6 +4,8 @@ public class A { static void foo() {} static int bar() {return 1;} + void nonStatic1() {} + void nonStatic2() {} } // FILE: B.java @@ -17,6 +19,8 @@ public class C { // FILE: 1.kt import A.foo import B.bar +import A.nonStatic1 +import B.nonStatic2 class E: A() { init { diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.txt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.txt index 99ad510f84f..cf2a77b8b82 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.txt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunVsImport.txt @@ -4,6 +4,8 @@ public open class A { public constructor A() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open fun nonStatic1(): kotlin.Unit + public/*package*/ open fun nonStatic2(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members @@ -15,6 +17,8 @@ public open class B : A { public constructor B() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic1(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic2(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members @@ -36,6 +40,8 @@ public final class E : A { public constructor E() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic1(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic2(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -43,6 +49,8 @@ public final class F : B { public constructor F() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic1(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic2(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -50,6 +58,8 @@ public final class Q : A { public constructor Q() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic1(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic2(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -57,5 +67,8 @@ public final class Z : A { public constructor Z() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic1(): kotlin.Unit + public/*package*/ open override /*1*/ /*fake_override*/ fun nonStatic2(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + diff --git a/compiler/testData/diagnostics/tests/scopes/kt1080.fir.kt b/compiler/testData/diagnostics/tests/scopes/kt1080.fir.kt index 996ee5f8bb4..017d9ac3d90 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt1080.fir.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt1080.fir.kt @@ -6,7 +6,7 @@ package kt1080 import reflect.Constructor import b.* -import d +import d import d.Test import b.d diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasesInImportDirectives.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasesInImportDirectives.fir.kt index d2d21ee4dda..ea4b5fd995a 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasesInImportDirectives.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasesInImportDirectives.fir.kt @@ -28,19 +28,19 @@ import test.ClassAlias import test.ClassAlias.Nested1 import test.ClassSample.Nested1.* -import test.ClassAlias.Nested1.* +import test.ClassAlias.Nested1.* import test.ObjectAlias import test.ObjectAlias.Nested2 import test.ObjectSample.Nested2.* -import test.ObjectAlias.Nested2.* +import test.ObjectAlias.Nested2.* import test.EnumAlias import test.EnumAlias.Nested3 import test.EnumSample.Nested3.* -import test.EnumAlias.Nested3.* +import test.EnumAlias.Nested3.* import test.EnumAlias.Entry diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index c8a41b51392..961cffc1087 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -26023,6 +26023,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/overloadStatic.kt"); } + @Test + @TestMetadata("staticFunAndPropertyImport.kt") + public void testStaticFunAndPropertyImport() throws Exception { + runTest("compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt"); + } + @Test @TestMetadata("staticFunVsImport.kt") public void testStaticFunVsImport() throws Exception {