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 5fa181412f2..b4bf9d1f510 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,6 +10,7 @@ import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.* import org.jetbrains.kotlin.fir.declarations.FirImport +import org.jetbrains.kotlin.name.FqName fun KtSourceElement.getChild(type: IElementType, index: Int = 0, depth: Int = -1, reverse: Boolean = false): KtSourceElement? { return getChild(setOf(type), index, depth, reverse) @@ -69,3 +70,10 @@ fun FirImport.getSourceForImportSegment(indexFromLast: Int): KtSourceElement? { return segmentSource.takeIf { it.elementType == KtNodeTypes.REFERENCE_EXPRESSION } ?: segmentSource.getChild(KtNodeTypes.REFERENCE_EXPRESSION, depth = 1, reverse = true) } + +/** + * Looks for the source element of the last segment + * of `importedFqName`. + */ +fun FirImport.getLastImportedFqNameSegmentSource(): KtSourceElement? = + source?.getChild(KtNodeTypes.REFERENCE_EXPRESSION, reverse = true) 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 e92c48c2911..176aca61b3e 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 @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationCheck import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.toInvisibleReferenceDiagnostic +import org.jetbrains.kotlin.fir.analysis.getLastImportedFqNameSegmentSource import org.jetbrains.kotlin.fir.analysis.getSourceForImportSegment import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass @@ -26,6 +27,8 @@ import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.providers.toSymbol +import org.jetbrains.kotlin.fir.resolve.transformers.PackageResolutionResult +import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.SymbolInternals @@ -71,11 +74,19 @@ object FirImportsChecker : FirFileChecker() { private fun checkAllUnderFromObject(import: FirImport, context: CheckerContext, reporter: DiagnosticReporter) { val fqName = import.importedFqName ?: return if (fqName.isRoot) return - val classId = ClassId.topLevel(fqName) - val classSymbol = classId.resolveToClass(context) ?: return - if (classSymbol.classKind.isObject) { + val classLike = when (val resolutionResult = resolveToPackageOrClass(context.session.symbolProvider, fqName)) { + is PackageResolutionResult.PackageOrClass -> resolutionResult.classSymbol ?: return + // Already an error import, already reported + is PackageResolutionResult.Error -> return + } + val classSymbol = classLike.fullyExpandedClass(context.session) + if (classSymbol != null && classSymbol.classKind.isObject) { reporter.reportOn(import.source, FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, classSymbol.classId.shortClassName, context) } + if (!classLike.fir.isVisible(context)) { + val source = import.getLastImportedFqNameSegmentSource() ?: error("`${import.source}` does not contain `$fqName`") + reporter.report(classLike.toInvisibleReferenceDiagnostic(source), context) + } } private fun checkCanBeImported(import: FirImport, context: CheckerContext, reporter: DiagnosticReporter) { diff --git a/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt b/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt index 8e7469d0908..ea5bcf3bdac 100644 --- a/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt @@ -17,7 +17,7 @@ public class B { // FILE: C.kt -import A.Nested.* +import A.Nested.* import B.JC.JC1 fun test() {