Prohibit to use enum entry as a type

#KT-14179 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-01-09 13:47:22 +03:00
parent 316da8331f
commit 76b0b785c5
14 changed files with 82 additions and 83 deletions
@@ -786,7 +786,7 @@ public interface Errors {
DiagnosticFactory0<KtSimpleNameExpression> CAST_NEVER_SUCCEEDS = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<KtTypeReference> DYNAMIC_NOT_ALLOWED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> IS_ENUM_ENTRY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> ENUM_ENTRY_AS_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtSimpleNameExpression> ENUM_ENTRY_AS_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory2<KtExpression, KotlinType, KotlinType> IMPLICIT_CAST_TO_ANY = DiagnosticFactory2.create(WARNING);
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,35 +40,6 @@ import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.addToStdlib.check
import java.util.*
fun KtDeclaration.checkTypeReferences(trace: BindingTrace) {
if (this is KtCallableDeclaration) {
typeReference?.checkNotEnumEntry(trace)
receiverTypeReference?.checkNotEnumEntry(trace)
}
if (this is KtDeclarationWithBody) {
for (parameter in valueParameters) {
parameter.typeReference?.checkNotEnumEntry(trace)
}
}
}
fun KtTypeReference.checkNotEnumEntry(trace: BindingTrace): Boolean {
var result = false
trace.bindingContext.get(TYPE, this)?.let {
val targetDescriptor = TypeUtils.getClassDescriptor(it)
if (targetDescriptor != null && DescriptorUtils.isEnumEntry(targetDescriptor)) {
trace.report(ENUM_ENTRY_AS_TYPE.on(this))
result = true
}
}
typeElement?.let {
for (typeArgument in it.typeArgumentsAsTypes) {
typeArgument?.checkNotEnumEntry(trace)
}
}
return result
}
internal class DeclarationsCheckerBuilder(
private val descriptorResolver: DescriptorResolver,
private val originalModifiersChecker: ModifiersChecker,
@@ -93,8 +64,6 @@ class DeclarationsChecker(
private val exposedChecker = ExposedVisibilityChecker(trace)
fun KtDeclaration.checkTypeReferences() = checkTypeReferences(trace)
fun process(bodiesResolveContext: BodiesResolveContext) {
for (file in bodiesResolveContext.files) {
checkModifiersAndAnnotationsInPackageDirective(file)
@@ -118,7 +87,6 @@ class DeclarationsChecker(
checkPrimaryConstructor(classOrObject, classDescriptor)
classOrObject.checkTypeReferences()
modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor)
identifierChecker.checkDeclaration(classOrObject, trace)
exposedChecker.checkClassHeader(classOrObject, classDescriptor)
@@ -126,14 +94,12 @@ class DeclarationsChecker(
for ((function, functionDescriptor) in bodiesResolveContext.functions.entries) {
checkFunction(function, functionDescriptor)
function.checkTypeReferences()
modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor)
identifierChecker.checkDeclaration(function, trace)
}
for ((property, propertyDescriptor) in bodiesResolveContext.properties.entries) {
checkProperty(property, propertyDescriptor)
property.checkTypeReferences()
modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor)
identifierChecker.checkDeclaration(property, trace)
}
@@ -259,7 +225,6 @@ class DeclarationsChecker(
}
private fun checkConstructorDeclaration(constructorDescriptor: ClassConstructorDescriptor, declaration: KtConstructor<*>) {
declaration.checkTypeReferences()
modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor)
identifierChecker.checkDeclaration(declaration, trace)
checkVarargParameters(trace, constructorDescriptor)
@@ -327,7 +292,6 @@ class DeclarationsChecker(
for (delegationSpecifier in classOrObject.getSuperTypeListEntries()) {
val typeReference = delegationSpecifier.typeReference ?: continue
typeReference.type()?.let { DescriptorResolver.checkBounds(typeReference, it, trace) }
typeReference.checkNotEnumEntry(trace)
}
if (classOrObject !is KtClass) return
@@ -841,7 +805,6 @@ class DeclarationsChecker(
for (accessorDescriptor in propertyDescriptor.accessors) {
val accessor = if (accessorDescriptor is PropertyGetterDescriptor) property.getter else property.setter
if (accessor != null) {
accessor.checkTypeReferences()
modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor)
identifierChecker.checkDeclaration(accessor, trace)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -622,7 +622,6 @@ public class DescriptorResolver {
@NotNull KotlinType upperBoundType,
BindingTrace trace
) {
if (DeclarationsCheckerKt.checkNotEnumEntry(upperBound, trace)) return;
if (!TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, upperBoundType)) {
trace.report(FINAL_UPPER_BOUND.on(upperBound, upperBoundType));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -120,7 +120,6 @@ class LocalVariableResolver(
ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor)
property.checkTypeReferences(context.trace)
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor)
identifierChecker.checkDeclaration(property, context.trace)
return Pair(typeInfo.replaceType(dataFlowAnalyzer.checkStatementType(property, context)), propertyDescriptor)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,9 +68,10 @@ class QualifiedExpressionResolver {
): TypeQualifierResolutionResult {
val ownerDescriptor = if (!isDebuggerContext) scope.ownerDescriptor else null
if (userType.qualifier == null) {
val descriptor = userType.referenceExpression?.let {
val classifier = scope.findClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it))
storeResult(trace, it, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false)
val descriptor = userType.referenceExpression?.let { expression ->
val classifier = scope.findClassifier(expression.getReferencedNameAsName(), KotlinLookupLocation(expression))
checkNotEnumEntry(classifier, trace, expression)
storeResult(trace, expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false)
classifier
}
@@ -106,13 +107,23 @@ class QualifiedExpressionResolver {
val lastPart = qualifierPartList.last()
val classifier = when (qualifier) {
is PackageViewDescriptor -> qualifier.memberScope.getContributedClassifier(lastPart.name, lastPart.location)
is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location)
is ClassDescriptor -> {
val descriptor = qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location)
checkNotEnumEntry(descriptor, trace, lastPart.expression)
descriptor
}
else -> null
}
storeResult(trace, lastPart.expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = isQualifier)
return TypeQualifierResolutionResult(qualifierPartList, classifier)
}
private fun checkNotEnumEntry(descriptor: DeclarationDescriptor?, trace: BindingTrace, expression: KtSimpleNameExpression) {
if (descriptor != null && DescriptorUtils.isEnumEntry(descriptor)) {
trace.report(Errors.ENUM_ENTRY_AS_TYPE.on(expression))
}
}
fun resolveDescriptorForDoubleColonLHS(
expression: KtExpression,
scope: LexicalScope,
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -353,8 +353,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
) {
if (actualType == null || noExpectedType(targetType) || targetType.isError()) return;
DeclarationsCheckerKt.checkNotEnumEntry(expression.getRight(), context.trace);
if (DynamicTypesKt.isDynamic(targetType)) {
KtTypeReference right = expression.getRight();
assert right != null : "We know target is dynamic, but RHS is missing";
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,8 +28,11 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope
@@ -109,7 +112,6 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
function.getValueParameters(), functionDescriptor.valueParameters, context.scope, context.dataFlowInfo, context.trace
)
function.checkTypeReferences(context.trace)
components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor)
components.identifierChecker.checkDeclaration(function, context.trace)
components.declarationsCheckerBuilder.withTrace(context.trace).checkFunction(function, functionDescriptor)