Prohibit using kotlin.Result as a return type in most cases

#KT-26659 In Progress
This commit is contained in:
Mikhail Zarechenskiy
2018-09-10 05:57:22 +03:00
parent 48add96e79
commit b1cd49dd7b
8 changed files with 299 additions and 1 deletions
@@ -334,6 +334,10 @@ public interface Errors {
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_INLINE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
// Result class
DiagnosticFactory0<PsiElement> RESULT_CLASS_IN_RETURN_TYPE = DiagnosticFactory0.create(ERROR);
// Secondary constructors
DiagnosticFactory0<KtConstructorDelegationReferenceExpression> CYCLIC_CONSTRUCTOR_DELEGATION_CALL = DiagnosticFactory0.create(ERROR);
@@ -665,6 +665,8 @@ public class DefaultErrorMessages {
MAP.put(RESERVED_MEMBER_INSIDE_INLINE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING);
MAP.put(SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, "Secondary constructors with bodies are reserved for for future releases");
MAP.put(RESULT_CLASS_IN_RETURN_TYPE, "'kotlin.Result' cannot be used as a return type");
MAP.put(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces");
MAP.put(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED, "Bounds are not allowed on type alias parameters");
@@ -120,7 +120,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
InlineClassDeclarationChecker,
PropertiesWithBackingFieldsInsideInlineClass(),
AnnotationClassTargetAndRetentionChecker(),
ReservedMembersAndConstructsForInlineClass()
ReservedMembersAndConstructsForInlineClass(),
ResultClassInReturnTypeChecker()
)
private val DEFAULT_CALL_CHECKERS = listOf(
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.resolve.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.types.KotlinType
class ResultClassInReturnTypeChecker : DeclarationChecker {
companion object {
private const val RESULT_NAME = "Result"
}
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration !is KtCallableDeclaration || descriptor !is CallableMemberDescriptor) return
val returnType = descriptor.returnType ?: return
if (isForbiddenReturnType(returnType, descriptor)) {
val typeReferenceOrDeclarationName = declaration.typeReference ?: declaration.nameIdentifier ?: return
context.trace.reportDiagnosticOnce(Errors.RESULT_CLASS_IN_RETURN_TYPE.on(typeReferenceOrDeclarationName))
}
}
private fun isForbiddenReturnType(returnType: KotlinType, declarationDescriptor: DeclarationDescriptor): Boolean {
val descriptor = returnType.constructor.declarationDescriptor ?: return false
if (!descriptor.isResultClass()) return false
if (declarationDescriptor is PropertyDescriptor || declarationDescriptor is PropertyGetterDescriptor) {
val visibility = (declarationDescriptor as DeclarationDescriptorWithVisibility).effectiveVisibility()
return when (visibility) {
is EffectiveVisibility.Private, is EffectiveVisibility.Local,
is EffectiveVisibility.InternalOrPackage, is EffectiveVisibility.InternalProtected,
is EffectiveVisibility.InternalProtectedBound -> false
is EffectiveVisibility.Public, is EffectiveVisibility.Protected,
is EffectiveVisibility.ProtectedBound -> true
}
}
return true
}
private fun DeclarationDescriptor.isResultClass(): Boolean {
val container = containingDeclaration ?: return false
return container is PackageFragmentDescriptor &&
container.fqName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME &&
name.asString() == RESULT_NAME
}
}
@@ -0,0 +1,116 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNUSED_EXPRESSION, -UNUSED_VARIABLE
// !LANGUAGE: +InlineClasses
typealias ResultAlias<T> = Result<T>
inline class InlineResult<out T>(private val r: Result<T>)
fun params(
r1: Result<Int>,
r2: Result<Int>?,
r3: ResultAlias<String>,
r4: List<Result<Int>>,
r5: InlineResult<Int>,
<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> r6: Result<Int>
) {}
class CtorParams(r1: Result<Int>)
fun returnTypePublic(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
internal fun returnTypeInternal(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
private fun returnTypePrivate(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
fun returnTypeNullable(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int>?<!> = TODO()
fun returnTypeAlias(): <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int><!> = TODO()
fun <!RESULT_CLASS_IN_RETURN_TYPE!>returnInferred<!>(r1: Result<Int>, r2: ResultAlias<Int>, b: Boolean) = if (b) r1 else r2
fun returnTypeInline(): InlineResult<Int> = TODO()
fun returnContainer(): List<Result<Int>> = TODO()
val topLevelP: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val <!RESULT_CLASS_IN_RETURN_TYPE!>topLevelPInferred<!> = topLevelP
internal val topLevelPInternal: Result<Int> = TODO()
private val topLevelPPrivate: Result<Int> = TODO()
private val topLevelPPrivateInferred = topLevelP
val asFunctional: () -> Result<Int> = TODO()
open class PublicCls(
val r1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<String><!>,
val r2: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int>?<!>,
val r3: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int><!>,
val r4: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int>?<!>,
val r5: InlineResult<Int>,
internal val r6: Result<Int>,
private val r7: Result<Int>,
val r8: List<Result<Int>>
) {
val p1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
var p2: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val p3: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int>?<!> = TODO()
val <!RESULT_CLASS_IN_RETURN_TYPE!>p4<!> = p1
internal val p5: Result<Int> = TODO()
private var p6: Result<Int> = TODO()
internal val p7 = p1
protected val <!RESULT_CLASS_IN_RETURN_TYPE!>p8<!> = p1
fun returnInCls(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
protected fun returnInClsProtected(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
private fun returnInClsPrivate(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
}
internal open class InternalCls(
val r1: Result<Int>,
val r2: ResultAlias<Int>?,
val r3: List<Result<Int>>
) {
companion object {
val cr1: Result<Int> = TODO()
private val cr2: Result<Int> = TODO()
}
val p1 = r1
val p2: Result<String> = TODO()
protected val p3 = p1
fun returnInInternal(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
protected fun returnInClsProtected(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
}
private class PrivateCls(
val r1: Result<Int>,
val r2: ResultAlias<Int>?,
val r3: List<Result<Int>>
) {
companion object {
val cr1: Result<Int> = TODO()
private val cr2: Result<Int> = TODO()
}
val p1 = r1
val p2: Result<String> = TODO()
fun returnInPrivate(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
}
fun local(r: Result<Int>) {
val l1: Result<Int>? = null
val l2 = r
fun localFun(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
class F {
val p1: Result<Int> = r
val p2 = r
}
}
fun <T> resultInGenericFun(r: Result<Int>): T = r <!UNCHECKED_CAST!>as T<!>
val asFunPublic: () -> Result<Int> = TODO()
private val asFun: () -> Result<Int>? = TODO()
@@ -0,0 +1,109 @@
package
private val asFun: () -> kotlin.Result<kotlin.Int>?
public val asFunPublic: () -> kotlin.Result<kotlin.Int>
public val asFunctional: () -> kotlin.Result<kotlin.Int>
public val topLevelP: kotlin.Result<kotlin.Int>
public val topLevelPInferred: kotlin.Result<kotlin.Int>
internal val topLevelPInternal: kotlin.Result<kotlin.Int>
private val topLevelPPrivate: kotlin.Result<kotlin.Int>
private val topLevelPPrivateInferred: kotlin.Result<kotlin.Int>
public fun local(/*0*/ r: kotlin.Result<kotlin.Int>): kotlin.Unit
public fun params(/*0*/ r1: kotlin.Result<kotlin.Int>, /*1*/ r2: kotlin.Result<kotlin.Int>?, /*2*/ r3: ResultAlias<kotlin.String> /* = kotlin.Result<kotlin.String> */, /*3*/ r4: kotlin.collections.List<kotlin.Result<kotlin.Int>>, /*4*/ r5: InlineResult<kotlin.Int>, /*5*/ vararg r6: kotlin.Result<kotlin.Int> /*kotlin.Array<out kotlin.Result<kotlin.Int>>*/): kotlin.Unit
public fun </*0*/ T> resultInGenericFun(/*0*/ r: kotlin.Result<kotlin.Int>): T
public fun returnContainer(): kotlin.collections.List<kotlin.Result<kotlin.Int>>
public fun returnInferred(/*0*/ r1: kotlin.Result<kotlin.Int>, /*1*/ r2: ResultAlias<kotlin.Int> /* = kotlin.Result<kotlin.Int> */, /*2*/ b: kotlin.Boolean): kotlin.Result<kotlin.Int>
public fun returnTypeAlias(): ResultAlias<kotlin.Int> /* = kotlin.Result<kotlin.Int> */
public fun returnTypeInline(): InlineResult<kotlin.Int>
internal fun returnTypeInternal(): kotlin.Result<kotlin.Int>
public fun returnTypeNullable(): kotlin.Result<kotlin.Int>?
private fun returnTypePrivate(): kotlin.Result<kotlin.Int>
public fun returnTypePublic(): kotlin.Result<kotlin.Int>
public final class CtorParams {
public constructor CtorParams(/*0*/ r1: kotlin.Result<kotlin.Int>)
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final inline class InlineResult</*0*/ out T> {
public constructor InlineResult</*0*/ out T>(/*0*/ r: kotlin.Result<T>)
private final val r: kotlin.Result<T>
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
internal open class InternalCls {
public constructor InternalCls(/*0*/ r1: kotlin.Result<kotlin.Int>, /*1*/ r2: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */, /*2*/ r3: kotlin.collections.List<kotlin.Result<kotlin.Int>>)
public final val p1: kotlin.Result<kotlin.Int>
public final val p2: kotlin.Result<kotlin.String>
protected final val p3: kotlin.Result<kotlin.Int>
public final val r1: kotlin.Result<kotlin.Int>
public final val r2: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */
public final val r3: kotlin.collections.List<kotlin.Result<kotlin.Int>>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
protected final fun returnInClsProtected(): kotlin.Result<kotlin.Int>
public final fun returnInInternal(): kotlin.Result<kotlin.Int>
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public companion object Companion {
private constructor Companion()
public final val cr1: kotlin.Result<kotlin.Int>
private final val cr2: kotlin.Result<kotlin.Int>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
private final class PrivateCls {
public constructor PrivateCls(/*0*/ r1: kotlin.Result<kotlin.Int>, /*1*/ r2: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */, /*2*/ r3: kotlin.collections.List<kotlin.Result<kotlin.Int>>)
public final val p1: kotlin.Result<kotlin.Int>
public final val p2: kotlin.Result<kotlin.String>
public final val r1: kotlin.Result<kotlin.Int>
public final val r2: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */
public final val r3: kotlin.collections.List<kotlin.Result<kotlin.Int>>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun returnInPrivate(): kotlin.Result<kotlin.Int>
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public companion object Companion {
private constructor Companion()
public final val cr1: kotlin.Result<kotlin.Int>
private final val cr2: kotlin.Result<kotlin.Int>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public open class PublicCls {
public constructor PublicCls(/*0*/ r1: kotlin.Result<kotlin.String>, /*1*/ r2: kotlin.Result<kotlin.Int>?, /*2*/ r3: ResultAlias<kotlin.Int> /* = kotlin.Result<kotlin.Int> */, /*3*/ r4: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */, /*4*/ r5: InlineResult<kotlin.Int>, /*5*/ r6: kotlin.Result<kotlin.Int>, /*6*/ r7: kotlin.Result<kotlin.Int>, /*7*/ r8: kotlin.collections.List<kotlin.Result<kotlin.Int>>)
public final val p1: kotlin.Result<kotlin.Int>
public final var p2: kotlin.Result<kotlin.Int>
public final val p3: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */
public final val p4: kotlin.Result<kotlin.Int>
internal final val p5: kotlin.Result<kotlin.Int>
private final var p6: kotlin.Result<kotlin.Int>
internal final val p7: kotlin.Result<kotlin.Int>
protected final val p8: kotlin.Result<kotlin.Int>
public final val r1: kotlin.Result<kotlin.String>
public final val r2: kotlin.Result<kotlin.Int>?
public final val r3: ResultAlias<kotlin.Int> /* = kotlin.Result<kotlin.Int> */
public final val r4: ResultAlias<kotlin.Int>? /* = kotlin.Result<kotlin.Int>? */
public final val r5: InlineResult<kotlin.Int>
internal final val r6: kotlin.Result<kotlin.Int>
private final val r7: kotlin.Result<kotlin.Int>
public final val r8: kotlin.collections.List<kotlin.Result<kotlin.Int>>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun returnInCls(): kotlin.Result<kotlin.Int>
private final fun returnInClsPrivate(): kotlin.Result<kotlin.Int>
protected final fun returnInClsProtected(): kotlin.Result<kotlin.Int>
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public typealias ResultAlias</*0*/ T> = kotlin.Result<T>
@@ -1658,6 +1658,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/unsupported.kt");
}
@TestMetadata("usageOfResultTypeInReturnType.kt")
public void testUsageOfResultTypeInReturnType() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/usageOfResultTypeInReturnType.kt");
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/callableReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1658,6 +1658,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/unsupported.kt");
}
@TestMetadata("usageOfResultTypeInReturnType.kt")
public void testUsageOfResultTypeInReturnType() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/usageOfResultTypeInReturnType.kt");
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/callableReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)