Support non-parenthesized annotations on functional types without receiver

^KT-31734 Fixed
This commit is contained in:
victor.petukhov
2019-07-05 19:02:05 +03:00
parent 60e3787800
commit 6a679d86ab
32 changed files with 11735 additions and 11 deletions
@@ -268,6 +268,8 @@ public interface Errors {
DiagnosticFactory1<PsiElement, FqName> EXPERIMENTAL_UNSIGNED_LITERALS = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<PsiElement, FqName> EXPERIMENTAL_UNSIGNED_LITERALS_ERROR = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> NON_PARENTHESIZED_ANNOTATIONS_ON_FUNCTIONAL_TYPES = DiagnosticFactory0.create(ERROR);
// Const
DiagnosticFactory0<PsiElement> CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> CONST_VAL_WITH_GETTER = DiagnosticFactory0.create(ERROR);
@@ -159,6 +159,8 @@ public class DefaultErrorMessages {
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS, "Unsigned literals are experimental and their usages should be marked with ''@{0}'' or ''@UseExperimental({0}::class)''", TO_STRING);
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS_ERROR, "Unsigned literals are experimental and their usages must be marked with ''@{0}'' or ''@UseExperimental({0}::class)''", TO_STRING);
MAP.put(NON_PARENTHESIZED_ANNOTATIONS_ON_FUNCTIONAL_TYPES, "Non parenthesized annotations on function types without receiver isn't yet supported (see KT-31734 for details)");
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
MAP.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members");
MAP.put(REDUNDANT_MODIFIER_IN_GETTER, "Visibility modifiers are redundant in getter");
@@ -34,6 +34,9 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
import org.jetbrains.kotlin.psi.debugText.getDebugText
import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.resolve.PossiblyBareType.bare
import org.jetbrains.kotlin.resolve.PossiblyBareType.type
@@ -69,6 +72,9 @@ class TypeResolver(
private val platformToKotlinClassMap: PlatformToKotlinClassMap,
private val languageVersionSettings: LanguageVersionSettings
) {
private val isNonParenthesizedAnnotationsOnFunctionalTypesEnabled =
languageVersionSettings.getFeatureSupport(LanguageFeature.NonParenthesizedAnnotationsOnFunctionalTypes) == LanguageFeature.State.ENABLED
open class TypeTransformerForTests {
open fun transformType(kotlinType: KotlinType): KotlinType? = null
}
@@ -129,12 +135,53 @@ class TypeResolver(
internal fun KtElementImplStub<*>.getAllModifierLists(): Array<out KtDeclarationModifierList> =
getStubOrPsiChildren(KtStubElementTypes.MODIFIER_LIST, KtStubElementTypes.MODIFIER_LIST.arrayFactory)
// TODO: remove this method and its usages in 1.4
private fun checkNonParenthesizedAnnotationsOnFunctionalType(
typeElement: KtFunctionType,
annotationEntries: List<KtAnnotationEntry>,
trace: BindingTrace
) {
val lastAnnotationEntry = annotationEntries.lastOrNull()
val isAnnotationsGroupedUsingBrackets =
lastAnnotationEntry?.getNextSiblingIgnoringWhitespaceAndComments()?.node?.elementType == KtTokens.RBRACKET
val hasAnnotationParentheses = lastAnnotationEntry?.valueArgumentList != null
val isFunctionalTypeStartingWithParentheses = typeElement.firstChild is KtParameterList
val hasSuspendModifierBeforeParentheses =
typeElement.getPrevSiblingIgnoringWhitespaceAndComments().run { this is KtDeclarationModifierList && hasSuspendModifier() }
if (lastAnnotationEntry != null &&
isFunctionalTypeStartingWithParentheses &&
!hasAnnotationParentheses &&
!isAnnotationsGroupedUsingBrackets &&
!hasSuspendModifierBeforeParentheses
) {
trace.report(Errors.NON_PARENTHESIZED_ANNOTATIONS_ON_FUNCTIONAL_TYPES.on(lastAnnotationEntry))
}
}
private fun resolveTypeAnnotations(c: TypeResolutionContext, modifierListsOwner: KtElementImplStub<*>): Annotations {
val modifierLists = modifierListsOwner.getAllModifierLists()
var result = Annotations.EMPTY
var isSplitModifierList = false
if (!isNonParenthesizedAnnotationsOnFunctionalTypesEnabled) {
val targetType = when (modifierListsOwner) {
is KtNullableType -> modifierListsOwner.innerType
is KtTypeReference -> modifierListsOwner.typeElement
else -> null
}
val annotationEntries = when (modifierListsOwner) {
is KtNullableType -> modifierListsOwner.modifierList?.annotationEntries
is KtTypeReference -> modifierListsOwner.annotationEntries
else -> null
}
if (targetType is KtFunctionType && annotationEntries != null) {
checkNonParenthesizedAnnotationsOnFunctionalType(targetType, annotationEntries, c.trace)
}
}
for (modifierList in modifierLists) {
if (isSplitModifierList) {
c.trace.report(MODIFIER_LIST_NOT_ALLOWED.on(modifierList))