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 3ad75a59405..347f92cc5cc 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 @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers import org.jetbrains.kotlin.fir.analysis.checkers.expression.* import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirConfusingWhenBranchSyntaxChecker +import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirUnderscoredTypeArgumentSyntaxChecker object CommonExpressionCheckers : ExpressionCheckers() { override val annotationCallCheckers: Set @@ -59,6 +60,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirSpreadOfNullableChecker, FirAssignmentOperatorCallChecker, FirNamedVarargChecker, + FirUnderscoredTypeArgumentSyntaxChecker, ) override val tryExpressionCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnderscoredTypeArgumentSyntaxChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnderscoredTypeArgumentSyntaxChecker.kt new file mode 100644 index 00000000000..3d301a8ce85 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirUnderscoredTypeArgumentSyntaxChecker.kt @@ -0,0 +1,68 @@ +/* + * 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 com.intellij.psi.PsiElement +import org.jetbrains.kotlin.* +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.annotations +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.diagnostics.userType +import org.jetbrains.kotlin.fir.analysis.buildChildSourceElement +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.isUnderscore +import org.jetbrains.kotlin.fir.analysis.diagnostics.* +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.psi.KtTypeProjection + +object FirUnderscoredTypeArgumentSyntaxChecker : FirExpressionSyntaxChecker() { + override fun isApplicable(element: FirFunctionCall, source: KtSourceElement): Boolean = + element.typeArguments.isNotEmpty() + + override fun checkPsi( + element: FirFunctionCall, + source: KtPsiSourceElement, + psi: PsiElement, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + for (typeProjection in element.typeArguments) { + val psiTypeArgument = typeProjection.source?.psi as? KtTypeProjection ?: continue + val typeReference = psiTypeArgument.typeReference ?: continue + + if (!typeReference.isPlaceholder) continue + + for (annotation in typeReference.annotationEntries) { + reporter.reportOn( + annotation.toKtPsiSourceElement(), FirErrors.UNSUPPORTED, + "annotations on an underscored type argument", context + ) + } + } + } + + override fun checkLightTree( + element: FirFunctionCall, + source: KtLightSourceElement, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + for (typeProjection in element.typeArguments) { + val lightTreeTypeArgument = typeProjection.source?.lighterASTNode ?: continue + + if (!source.treeStructure.userType(lightTreeTypeArgument).toString().isUnderscore) continue + + val annotations = source.treeStructure.annotations(lightTreeTypeArgument) ?: continue + + for (annotation in annotations) { + reporter.reportOn( + source.buildChildSourceElement(annotation), FirErrors.UNSUPPORTED, + "annotations on an underscored type argument", context + ) + } + } + } +} diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt index 4f715712c91..100dfe4800b 100644 --- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt @@ -1192,6 +1192,17 @@ fun FlyweightCapableTreeStructure.inlineModifier(declaration: Li fun FlyweightCapableTreeStructure.typeParametersList(declaration: LighterASTNode): LighterASTNode? = findChildByType(declaration, KtNodeTypes.TYPE_PARAMETER_LIST) +fun FlyweightCapableTreeStructure.annotations(node: LighterASTNode): List? { + val typeReference = findChildByType(node, KtNodeTypes.TYPE_REFERENCE) ?: return null + val modifiers = modifierList(typeReference) ?: return null + return collectDescendantsOfType(modifiers, KtNodeTypes.ANNOTATION_ENTRY) +} + +fun FlyweightCapableTreeStructure.userType(node: LighterASTNode): LighterASTNode? { + val typeReference = findChildByType(node, KtNodeTypes.TYPE_REFERENCE) ?: return null + return findChildByType(typeReference, KtNodeTypes.USER_TYPE) +} + private fun FlyweightCapableTreeStructure.supertypesList(node: LighterASTNode): LighterASTNode? = findChildByType(node, KtNodeTypes.SUPER_TYPE_LIST)