From 9ca96ebbd2f2917ec9a3a5b5dfacecfcb114b918 Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 7 Sep 2021 13:10:37 +0300 Subject: [PATCH] FIR: Add FirVisibilityQualifierChecker --- .../checkers/CommonExpressionCheckers.kt | 1 + .../FirVisibilityQualifierChecker.kt | 58 +++++++++++++++++++ .../nestedClassInPrivateClassObject.fir.kt | 4 +- .../ImportPrivateMemberFromOtherFile.fir.kt | 4 +- .../ImportPrivateMembersWithStar.fir.kt | 4 +- .../j+k/privateNestedClassStaticMember.fir.kt | 4 +- .../tests/typealias/privateInFile.fir.kt | 4 +- 7 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirVisibilityQualifierChecker.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index a1ed6ea7409..b75a8d6df5b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -135,6 +135,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirStandaloneQualifierChecker, FirOptInUsageQualifierChecker, FirDeprecatedQualifierChecker, + FirVisibilityQualifierChecker, ) override val equalityOperatorCallCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirVisibilityQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirVisibilityQualifierChecker.kt new file mode 100644 index 00000000000..408f3d88646 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirVisibilityQualifierChecker.kt @@ -0,0 +1,58 @@ +/* + * 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.expression + +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirTypeAlias +import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType +import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier +import org.jetbrains.kotlin.fir.getOwnerLookupTag +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.types.toSymbol +import org.jetbrains.kotlin.fir.visibilityChecker + +object FirVisibilityQualifierChecker : FirResolvedQualifierChecker() { + override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { + checkClassLikeSymbol(expression.symbol ?: return, expression, context, reporter) + } + + @OptIn(SymbolInternals::class) + private fun checkClassLikeSymbol( + symbol: FirClassLikeSymbol<*>, + expression: FirResolvedQualifier, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val firFile = context.containingDeclarations.firstOrNull() as? FirFile ?: return + val firClassLikeDeclaration = symbol.fir + if (firClassLikeDeclaration !is FirMemberDeclaration) return + + if (!context.session.visibilityChecker.isVisible( + firClassLikeDeclaration, context.session, firFile, context.containingDeclarations, + dispatchReceiver = null, + )) { + reporter.reportOn(expression.source, FirErrors.INVISIBLE_REFERENCE, symbol, context) + return + } + + if (firClassLikeDeclaration is FirTypeAlias) { + (firClassLikeDeclaration.expandedConeType?.toSymbol(context.session) as? FirClassLikeSymbol)?.let { + checkClassLikeSymbol(it, expression, context, reporter) + } + } + + symbol.getOwnerLookupTag()?.toSymbol(context.session)?.let { + checkClassLikeSymbol(it, expression, context, reporter) + } + } +} diff --git a/compiler/testData/diagnostics/tests/classObjects/nestedClassInPrivateClassObject.fir.kt b/compiler/testData/diagnostics/tests/classObjects/nestedClassInPrivateClassObject.fir.kt index 73796dc8b0e..a4b5beffe39 100644 --- a/compiler/testData/diagnostics/tests/classObjects/nestedClassInPrivateClassObject.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/nestedClassInPrivateClassObject.fir.kt @@ -10,6 +10,6 @@ class A { } } -fun f1() = A.Companion.B.C +fun f1() = A.Companion.B.C -fun f2() = A.Companion.B.C.foo() +fun f2() = A.Companion.B.C.foo() diff --git a/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt b/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt index af6f1c5e93f..12bda92ac38 100644 --- a/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/ImportPrivateMemberFromOtherFile.fir.kt @@ -21,6 +21,6 @@ import A.Nested.* import B.JC.JC1 fun test() { - O1 + O1 JC1() -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/imports/ImportPrivateMembersWithStar.fir.kt b/compiler/testData/diagnostics/tests/imports/ImportPrivateMembersWithStar.fir.kt index ca8d7b91a77..3f44adf4ce7 100644 --- a/compiler/testData/diagnostics/tests/imports/ImportPrivateMembersWithStar.fir.kt +++ b/compiler/testData/diagnostics/tests/imports/ImportPrivateMembersWithStar.fir.kt @@ -28,5 +28,5 @@ fun testAccess() { E1 NestedEntry A1() - A2 -} \ No newline at end of file + A2 +} diff --git a/compiler/testData/diagnostics/tests/j+k/privateNestedClassStaticMember.fir.kt b/compiler/testData/diagnostics/tests/j+k/privateNestedClassStaticMember.fir.kt index d0a40b6be97..a50380e82b8 100644 --- a/compiler/testData/diagnostics/tests/j+k/privateNestedClassStaticMember.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/privateNestedClassStaticMember.fir.kt @@ -14,5 +14,5 @@ public class Foo { // FILE: 1.kt fun main() { - javaPackage.Foo.Bar.doSmth() -} \ No newline at end of file + javaPackage.Foo.Bar.doSmth() +} diff --git a/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt b/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt index 333368c030a..8524ddd6fa6 100644 --- a/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt @@ -7,10 +7,10 @@ private class C { private typealias TA = C private val test1: C = C() -private val test1co: C.Companion = C +private val test1co: C.Companion = C private val test2: TA = TA() -private val test2co = TA +private val test2co = TA // FILE: file2.kt private val test1: C = C()