From 18f7a760bb938c8e1a517351544fce1e3bdce248 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Mon, 25 Oct 2021 17:37:38 -0700 Subject: [PATCH] FIR checker: report unresolved reference in imports Compared to FE1.0, instead of using UNRESOLVED_REFERENCE, a new UNRESOLVED_IMPORT diagnostic is introduced. This is so that we can use a different positioning strategy to highlight the last part of the import if the entire import is passed. Also, this change fixed some incorrectly rejected imports in FIR. Such cases are covered the newly added test file staticFunAndPropertyImport.kt --- .../fir/components/KtFirReferenceShortener.kt | 11 +- .../diagnostics/KtFirDataClassConverters.kt | 7 + .../api/fir/diagnostics/KtFirDiagnostics.kt | 5 + .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 6 + ...CompilerTestFE10TestdataTestGenerated.java | 6 + ...irOldFrontendDiagnosticsTestGenerated.java | 6 + ...DiagnosticsWithLightTreeTestGenerated.java | 6 + .../diagnostics/FirDiagnosticsList.kt | 3 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../kotlin/fir/analysis/FirSourceUtils.kt | 22 +-- .../LighterTreeElementFinderByType.kt | 6 +- .../fir/analysis/PsiElementFinderByType.kt | 6 +- .../checkers/CommonDeclarationCheckers.kt | 1 + .../checkers/declaration/FirImportsChecker.kt | 133 +++++++++++++----- .../FirUnresolvedInMiddleOfImportChecker.kt | 95 +++++++++++++ .../diagnostics/FirErrorsDefaultMessages.kt | 2 + .../coneDiagnosticToFirDiagnostic.kt | 1 + .../converter/DeclarationsConverter.kt | 19 ++- .../FirImportResolveTransformer.kt | 31 ++-- .../fir/declarations/ImplicitReceiverUtils.kt | 2 +- .../resolve/diagnostics/ConeDiagnostics.kt | 5 + .../diagnostics/tests/imports/Imports.fir.kt | 12 +- .../tests/imports/WrongImport.fir.kt | 24 ++-- .../diagnostics/tests/imports/kt13112.fir.kt | 4 +- .../tests/imports/twoImportLists.fir.kt | 12 +- .../tests/regressions/kt762.fir.kt | 2 +- .../statics/staticFunAndPropertyImport.kt | 45 ++++++ .../statics/staticFunAndPropertyImport.txt | 61 ++++++++ .../inheritance/statics/staticFunVsImport.kt | 4 + .../inheritance/statics/staticFunVsImport.txt | 13 ++ .../diagnostics/tests/scopes/kt1080.fir.kt | 2 +- .../typeAliasesInImportDirectives.fir.kt | 6 +- .../test/runners/DiagnosticTestGenerated.java | 6 + 33 files changed, 470 insertions(+), 95 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnresolvedInMiddleOfImportChecker.kt create mode 100644 compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.kt create mode 100644 compiler/testData/diagnostics/tests/scopes/inheritance/statics/staticFunAndPropertyImport.txt 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 {