[FIR] Deprecate using typealias as callable qualifier in import

^KT-64350 Fixed
This commit is contained in:
Roman Efremov
2024-02-13 11:33:29 +01:00
committed by Space Team
parent 802366064d
commit 3994e3f63a
19 changed files with 157 additions and 10 deletions
@@ -4889,6 +4889,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT.errorFactory) { firDiagnostic ->
TypealiasAsCallableQualifierInImportErrorImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT.warningFactory) { firDiagnostic ->
TypealiasAsCallableQualifierInImportWarningImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.ILLEGAL_SUSPEND_FUNCTION_CALL) { firDiagnostic ->
IllegalSuspendFunctionCallImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a),
@@ -3406,6 +3406,18 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = OperatorRenamedOnImport::class
}
interface TypealiasAsCallableQualifierInImportError : KtFirDiagnostic<KtImportDirective> {
override val diagnosticClass get() = TypealiasAsCallableQualifierInImportError::class
val typealiasName: Name
val originalClassName: Name
}
interface TypealiasAsCallableQualifierInImportWarning : KtFirDiagnostic<KtImportDirective> {
override val diagnosticClass get() = TypealiasAsCallableQualifierInImportWarning::class
val typealiasName: Name
val originalClassName: Name
}
interface IllegalSuspendFunctionCall : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = IllegalSuspendFunctionCall::class
val suspendCallable: KtSymbol
@@ -4106,6 +4106,20 @@ internal class OperatorRenamedOnImportImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtImportDirective>(firDiagnostic, token), KtFirDiagnostic.OperatorRenamedOnImport
internal class TypealiasAsCallableQualifierInImportErrorImpl(
override val typealiasName: Name,
override val originalClassName: Name,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtImportDirective>(firDiagnostic, token), KtFirDiagnostic.TypealiasAsCallableQualifierInImportError
internal class TypealiasAsCallableQualifierInImportWarningImpl(
override val typealiasName: Name,
override val originalClassName: Name,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtImportDirective>(firDiagnostic, token), KtFirDiagnostic.TypealiasAsCallableQualifierInImportWarning
internal class IllegalSuspendFunctionCallImpl(
override val suspendCallable: KtSymbol,
firDiagnostic: KtPsiDiagnostic,
@@ -1732,6 +1732,14 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val OPERATOR_RENAMED_ON_IMPORT by error<KtImportDirective>(PositioningStrategy.IMPORT_LAST_NAME)
val TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT by deprecationError<KtImportDirective>(
LanguageFeature.ProhibitTypealiasAsCallableQualifierInImport,
PositioningStrategy.IMPORT_LAST_BUT_ONE_NAME,
) {
parameter<Name>("typealiasName")
parameter<Name>("originalClassName")
}
}
val SUSPEND by object : DiagnosticGroup("Suspend errors") {
@@ -93,6 +93,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
QUESTION_MARK_BY_TYPE,
ANNOTATION_USE_SITE,
IMPORT_LAST_NAME,
IMPORT_LAST_BUT_ONE_NAME,
DATA_MODIFIER,
SPREAD_OPERATOR,
DECLARATION_WITH_BODY,
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMeth
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitScriptTopLevelInnerClasses
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitSingleNamedFunctionAsExpression
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitTypealiasAsCallableQualifierInImport
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
import org.jetbrains.kotlin.config.LanguageFeature.RestrictRetentionForExpressionAnnotations
import org.jetbrains.kotlin.config.LanguageFeature.RestrictionOfValReassignmentViaBackingField
@@ -858,6 +859,7 @@ object FirErrors {
val CANNOT_BE_IMPORTED: KtDiagnosticFactory1<Name> by error1<KtImportDirective, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
val CONFLICTING_IMPORT: KtDiagnosticFactory1<Name> by error1<KtImportDirective, Name>(SourceElementPositioningStrategies.IMPORT_ALIAS)
val OPERATOR_RENAMED_ON_IMPORT: KtDiagnosticFactory0 by error0<KtImportDirective>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
val TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT: KtDiagnosticFactoryForDeprecation2<Name, Name> by deprecationError2<KtImportDirective, Name, Name>(ProhibitTypealiasAsCallableQualifierInImport, SourceElementPositioningStrategies.IMPORT_LAST_BUT_ONE_NAME)
// Suspend errors
val ILLEGAL_SUSPEND_FUNCTION_CALL: KtDiagnosticFactory1<FirBasedSymbol<*>> by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
@@ -95,7 +95,8 @@ object FirImportsChecker : FirFileChecker(MppCheckerKind.Common) {
val symbolProvider = context.session.symbolProvider
val parentClassId = (import as? FirResolvedImport)?.resolvedParentClassId
if (parentClassId != null) {
val parentClassSymbol = parentClassId.resolveToClass(context) ?: return
val parentClassLikeSymbol = parentClassId.resolveToClassLike(context) ?: return
val parentClassSymbol = parentClassLikeSymbol.fullyExpandedClass(context.session) ?: return
fun reportInvisibleParentClasses(classSymbol: FirRegularClassSymbol, depth: Int) {
if (!classSymbol.isVisible(context)) {
@@ -109,7 +110,14 @@ object FirImportsChecker : FirFileChecker(MppCheckerKind.Common) {
reportInvisibleParentClasses(parentClassSymbol, 1)
when (val status = parentClassSymbol.getImportStatusOfCallableMembers(context, importedName)) {
ImportStatus.OK -> return
ImportStatus.OK -> {
if (parentClassLikeSymbol is FirTypeAliasSymbol) {
reporter.reportOn(
import.source, FirErrors.TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT,
parentClassLikeSymbol.name, parentClassSymbol.name, context
)
}
}
is ImportStatus.Invisible -> {
val source = import.getSourceForImportSegment(0)
reporter.report(status.symbol.toInvisibleReferenceDiagnostic(source), context)
@@ -237,8 +245,12 @@ object FirImportsChecker : FirFileChecker(MppCheckerKind.Common) {
}
}
private fun ClassId.resolveToClassLike(context: CheckerContext): FirClassLikeSymbol<*>? {
return context.session.symbolProvider.getClassLikeSymbolByClassId(this)
}
private fun ClassId.resolveToClass(context: CheckerContext): FirRegularClassSymbol? {
val classSymbol = context.session.symbolProvider.getClassLikeSymbolByClassId(this) ?: return null
val classSymbol = resolveToClassLike(context) ?: return null
return when (classSymbol) {
is FirRegularClassSymbol -> classSymbol
is FirTypeAliasSymbol -> classSymbol.fullyExpandedClass(context.session)
@@ -611,6 +611,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.THROWABLE_TYPE_MI
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_EXPANDS_TO_ARRAY_OF_NOTHINGS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_EXPANSION_DEPRECATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR
@@ -2511,6 +2512,13 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
TO_STRING
)
map.put(OPERATOR_RENAMED_ON_IMPORT, "Operator renamed to a different operator on import.")
map.put(
TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT,
"Cannot use typealias ''{0}'' as a callable qualifier in import. " +
"Use original class ''{1}'' instead or rewrite calls with ''{0}'' as a qualifier. " +
"See https://youtrack.jetbrains.com/issue/KT-64431.",
NAME, NAME
)
// Suspend
map.put(
@@ -1048,6 +1048,19 @@ object LightTreePositioningStrategies {
}
}
val IMPORT_LAST_BUT_ONE_NAME: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
override fun mark(
node: LighterASTNode,
startOffset: Int,
endOffset: Int,
tree: FlyweightCapableTreeStructure<LighterASTNode>
): List<TextRange> {
val references = tree.collectDescendantsOfType(node, KtNodeTypes.REFERENCE_EXPRESSION)
val nodeToMark = references.elementAtOrNull(references.size - 2) ?: node
return markElement(nodeToMark, startOffset, endOffset, tree, node)
}
}
val IMPORT_ALIAS: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
override fun mark(
node: LighterASTNode,
@@ -17,6 +17,8 @@ import org.jetbrains.kotlin.lexer.KtTokens.MODALITY_MODIFIERS
import org.jetbrains.kotlin.lexer.KtTokens.VISIBILITY_MODIFIERS
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.sure
object PositioningStrategies {
@@ -1013,6 +1015,20 @@ object PositioningStrategies {
}
}
@OptIn(UnsafeCastFunction::class)
val IMPORT_LAST_BUT_ONE_NAME: PositioningStrategy<KtImportDirective> = object : PositioningStrategy<KtImportDirective>() {
override fun mark(element: KtImportDirective): List<TextRange> {
element.importedReference
?.safeAs<KtDotQualifiedExpression>()
?.receiverExpression
?.safeAs<KtDotQualifiedExpression>()
?.selectorExpression
?.let { return markElement(it) }
return super.mark(element)
}
}
val LABEL: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
override fun mark(element: KtElement): List<TextRange> {
return super.mark((element as? KtExpressionWithLabel)?.labelQualifier ?: element)
@@ -286,6 +286,11 @@ object SourceElementPositioningStrategies {
PositioningStrategies.IMPORT_LAST_NAME
)
val IMPORT_LAST_BUT_ONE_NAME = SourceElementPositioningStrategy(
LightTreePositioningStrategies.IMPORT_LAST_BUT_ONE_NAME,
PositioningStrategies.IMPORT_LAST_BUT_ONE_NAME,
)
val SPREAD_OPERATOR = SourceElementPositioningStrategy(
LightTreePositioningStrategies.SPREAD_OPERATOR,
PositioningStrategies.SPREAD_OPERATOR
@@ -0,0 +1,15 @@
// FILE: 1.kt
package bar
typealias HostAlias = Host
object Host {
fun foo() {}
}
// FILE: 2.kt
import bar.<!TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT_WARNING("HostAlias; Host")!>HostAlias<!>.foo
fun test() {
foo()
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// FILE: 1.kt
package bar
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// FILE: 1.kt
package bar
@@ -9,7 +8,7 @@ object Host {
}
// FILE: 2.kt
import bar.HostAlias.foo
import bar.<!TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT_WARNING("HostAlias; Host")!>HostAlias<!>.foo
fun test() {
<!UNRESOLVED_REFERENCE!>foo<!>()
@@ -0,0 +1,28 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_JAVAC
// FILE: test/jv/JavaSample.java
package test.jv;
public class JavaSample {
public static void member() {}
}
// FILE: foo.kt
package test.kot
typealias JavaAlias = test.jv.JavaSample
// FILE: test.kt
import test.kot.JavaAlias
import test.kot.<!TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT_WARNING!>JavaAlias<!>.member
fun foo(
sample: <!UNRESOLVED_REFERENCE!>JavaSample<!>,
alias: JavaAlias
) {
member()
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_JAVAC
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_JAVAC
@@ -19,7 +18,7 @@ typealias JavaAlias = test.jv.JavaSample
// FILE: test.kt
import test.kot.JavaAlias
import test.kot.JavaAlias.member
import test.kot.<!TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT_WARNING!>JavaAlias<!>.member
fun foo(
sample: <!UNRESOLVED_REFERENCE!>JavaSample<!>,
@@ -42,6 +42,6 @@ import test.EnumAlias.Nested3
import test.EnumSample.Nested3.*
import test.EnumAlias.<!UNRESOLVED_IMPORT!>Nested3<!>.*
import test.EnumAlias.Entry
import test.<!TYPEALIAS_AS_CALLABLE_QUALIFIER_IN_IMPORT_WARNING!>EnumAlias<!>.Entry
fun f() {}
@@ -323,6 +323,7 @@ enum class LanguageFeature(
JsAllowInvalidCharsIdentifiersEscaping(KOTLIN_2_1, kind = OTHER), // KT-31799
SupportJavaErrorEnhancementOfArgumentsOfWarningLevelEnhanced(KOTLIN_2_1, kind = BUG_FIX), // KT-63209
ProhibitPrivateOperatorCallInInline(KOTLIN_2_1, kind = BUG_FIX), // KT-65494
ProhibitTypealiasAsCallableQualifierInImport(KOTLIN_2_1, kind = BUG_FIX), // KT-64350
// End of 2.* language features --------------------------------------------------